Skip to main content

LoadedProject

Struct LoadedProject 

Source
pub struct LoadedProject { /* private fields */ }
Expand description

A fully loaded zero-Rust game project.

Implementations§

Source§

impl LoadedProject

Source

pub fn load(root: &Path) -> Result<Self>

Load the project rooted at root (the directory containing .dotzuki-editor.json) from disk. Convenience for load_with_files over a DiskFiles.

§Errors

Fails on a missing/unparseable manifest or any DSL diagnostic.

Examples found in repository?
examples/menu_accept.rs (line 81)
76fn main() {
77    let mut args = std::env::args().skip(1);
78    let dir = args.next().expect("usage: menu_accept <project-dir> [shot-dir]");
79    let shot_dir = args.next().map(PathBuf::from);
80
81    let project = LoadedProject::load(Path::new(&dir)).expect("load project");
82    let mut game = RunnerGame::new(
83        project,
84        RunnerOptions {
85            headless: true,
86            fresh: true,
87            // Deterministic battles: always hit, 89% variance, never crit.
88            rng_script: Some(vec![50, 100, 1]),
89            ..RunnerOptions::default()
90        },
91    )
92    .expect("boot game");
93
94    dismiss(&mut game); // StartTown main
95    println!("== 1. the shop ==");
96    println!("money at boot: {} (manifest shop.startMoney)", game.money());
97
98    // Talk to the Shopkeeper at (13,10): the shop opens on the spot.
99    game.debug_place(12, 10, Direction::Right);
100    press_a(&mut game);
101    let rows = game.shop_lines().expect("shop open");
102    println!("shop shelf: {rows:?}");
103    snap(&mut game, &shot_dir, "shop");
104
105    // Buy one Potion: 100 → 80 G, inventory 3 → 4.
106    let before = game.money();
107    press_a(&mut game);
108    let rows = game.shop_lines().expect("shop still open");
109    println!(
110        "bought a Potion: money {before} → {} G; inventory {:?}",
111        game.money(),
112        game.inventory().expect("inventory materialized")
113    );
114    println!("shop note: {:?}", rows.last());
115    snap(&mut game, &shot_dir, "shop-bought");
116    assert_eq!(game.money(), 80, "20 G charged");
117    assert_eq!(game.inventory().unwrap().get("potion"), Some(&4));
118    press_a(&mut game); // dismiss the note
119
120    // B exits; the scene resumes with its follow-up line.
121    press(&mut game, GbButton::B);
122    let page = game.dialogue_text().expect("scene resumed after the shop");
123    println!("scene resumed with: {page:?}");
124    assert!(page.contains("Come again!"), "page: {page:?}");
125    dismiss(&mut game);
126
127    println!("\n== 2. the whiteout ==");
128    // Talk to the Hermit at (11,10) and lose on purpose (overwhelming Slime).
129    game.debug_place(12, 10, Direction::Left);
130    press_a(&mut game); // "Something stirs…"
131    press_a(&mut game); // → battle
132    let mut last_log: Vec<String> = Vec::new();
133    for _ in 0..120 {
134        let Some(battle) = game.battle() else { break };
135        last_log = battle.log().to_vec();
136        press_a(&mut game);
137    }
138    println!("lost battle log:");
139    for line in &last_log {
140        println!("  {line}");
141    }
142    assert_eq!(last_log.last().map(String::as_str), Some("You lost the battle…"));
143
144    // The scene's post-lose text still plays…
145    let page = game.dialogue_text().expect("post-lose text");
146    println!("post-lose text: {page:?}");
147    assert!(page.contains("no match"), "page: {page:?}");
148    press_a(&mut game); // scene finishes → whiteout
149
150    // …then the whiteout: blackout first, then the collapsed line.
151    assert!(game.whiteout_active(), "whiteout armed");
152    idle(&mut game, 10);
153    snap(&mut game, &shot_dir, "whiteout-blackout");
154    idle(&mut game, 25);
155    let page = game.dialogue_text().expect("whiteout message");
156    println!("whiteout message: {page:?}");
157    assert!(page.contains("collapsed"), "page: {page:?}");
158    snap(&mut game, &shot_dir, "whiteout-message");
159
160    // Landing it: party healed to full, back at the entry spawn, flags kept.
161    press_a(&mut game);
162    assert!(!game.whiteout_active());
163    println!("after the whiteout:");
164    println!("  map: {:?} tile: {:?}", game.current_map_id(), game.player_tile());
165    for m in game.party_state().expect("party state") {
166        println!("  {} hp {} mp {} status {:?}", m.id, m.hp, m.mp, m.status);
167    }
168    println!("  __played_main_StartTown flag kept: {}", game.flag("__played_main_StartTown"));
169    assert_eq!(game.current_map_id(), Some("StartTown"));
170    assert!(game
171        .party_state()
172        .unwrap()
173        .iter()
174        .all(|m| m.hp > 0 && m.status.is_none()));
175    snap(&mut game, &shot_dir, "whiteout-after");
176
177    println!("\nacceptance OK");
178}
More examples
Hide additional examples
examples/levels_accept.rs (line 75)
69fn main() {
70    let mut args = std::env::args().skip(1);
71    let dir = args.next().expect("usage: levels_accept <project-dir> [shot-dir]");
72    let shot_dir = args.next().map(PathBuf::from);
73
74    let save_file = Path::new(&dir).join(".dotzuki-save.json");
75    let project = LoadedProject::load(Path::new(&dir)).expect("load project");
76    let mut game = RunnerGame::new(
77        project,
78        RunnerOptions {
79            headless: true,
80            fresh: true,
81            write_saves: true,
82            save_file: Some(save_file.clone()),
83            // Deterministic battles: always hit, 89% variance, never crit.
84            rng_script: Some(vec![50, 100, 1]),
85            ..RunnerOptions::default()
86        },
87    )
88    .expect("boot game");
89
90    // Auto-A drives everything: dialogue pages, battle narration, and the
91    // Fight → first-skill picks. Back-to-back `startBattle` commands swap
92    // Battle→Battle INSIDE one update, so a new battle is detected by the
93    // log resetting, not just by a not-in-battle gap.
94    let mut battle_no = 0usize;
95    let mut completed = 0usize;
96    let mut last_log: Vec<String> = Vec::new();
97    let mut was_in_battle = false;
98    let mut snapped_battle = false;
99
100    for frame_no in 0..6000u32 {
101        if frame_no % 4 == 0 {
102            frame(&mut game, GbButton::A.bit_mask());
103        } else {
104            idle(&mut game, 1);
105        }
106
107        let in_battle = game.battle().is_some();
108        if in_battle {
109            let log_len = game.battle().unwrap().log().len();
110            let new_battle = !was_in_battle || log_len < last_log.len();
111            if new_battle {
112                if was_in_battle {
113                    // Seamless Battle→Battle swap: close the previous one
114                    // out (the party state is already harvested).
115                    completed += 1;
116                    println!("\nbattle {completed} log:");
117                    for line in &last_log {
118                        println!("  {line}");
119                    }
120                    print_party(&game, &format!("after battle {completed}"));
121                    println!();
122                    if completed == 2 {
123                        break;
124                    }
125                }
126                battle_no += 1;
127                let battle = game.battle().unwrap();
128                println!("battle {battle_no} starts:");
129                for c in battle.party() {
130                    println!(
131                        "  {} level {} exp {} hp {}/{} mp {}/{} atk {}",
132                        c.name, c.level, c.exp, c.hp, c.max_hp, c.mp, c.max_mp, c.attack
133                    );
134                }
135                if battle_no == 2 && !snapped_battle {
136                    snapped_battle = true;
137                    snap(&mut game, &shot_dir, "battle2-start");
138                }
139            }
140            last_log = game.battle().unwrap().log().to_vec();
141        } else if was_in_battle {
142            completed += 1;
143            println!("\nbattle {completed} log:");
144            for line in &last_log {
145                println!("  {line}");
146            }
147            print_party(&game, &format!("after battle {completed}"));
148            println!();
149            last_log.clear();
150            if completed == 2 {
151                break;
152            }
153        }
154        was_in_battle = in_battle;
155    }
156    if completed < 2 {
157        eprintln!("harness: only {completed} battle(s) completed within the frame cap");
158        std::process::exit(1);
159    }
160
161    // Dismiss the post-battle text so the scene finishes (the save is
162    // written at that stable point).
163    for _ in 0..40 {
164        if game.dialogue_text().is_none() {
165            break;
166        }
167        press_a(&mut game);
168    }
169    assert!(game.flag("SLIMES_BEATEN"), "the scene ran to its end");
170
171    // The Party view: Lv + EXP progress on the member rows.
172    frame(&mut game, GbButton::Start.bit_mask());
173    idle(&mut game, 1);
174    press_a(&mut game); // Party
175    println!("party view:");
176    for line in game.menu_lines().expect("party view open") {
177        println!("  {line}");
178    }
179    snap(&mut game, &shot_dir, "party-view");
180    frame(&mut game, GbButton::B.bit_mask());
181    idle(&mut game, 1);
182    frame(&mut game, GbButton::B.bit_mask());
183    idle(&mut game, 1);
184
185    // Save round trip: a fresh boot resumes level/exp from the save.
186    println!("\nsave round trip ({}):", save_file.display());
187    let project = LoadedProject::load(Path::new(&dir)).expect("reload project");
188    let game = RunnerGame::new(
189        project,
190        RunnerOptions {
191            headless: true,
192            save_file: Some(save_file),
193            rng_script: Some(vec![50, 100, 1]),
194            ..RunnerOptions::default()
195        },
196    )
197    .expect("boot from save");
198    print_party(&game, "resumed from the save");
199    assert!(
200        game.party_state().is_some_and(|p| p[0].level > 1),
201        "level must survive the save round trip"
202    );
203    println!("\nacceptance OK");
204}
examples/battle_accept.rs (line 51)
46fn main() {
47    let mut args = std::env::args().skip(1);
48    let dir = args.next().expect("usage: battle_accept <project-dir> [shot-dir]");
49    let shot_dir = args.next().map(PathBuf::from);
50
51    let project = LoadedProject::load(Path::new(&dir)).expect("load project");
52    let mut game = RunnerGame::new(
53        project,
54        RunnerOptions {
55            headless: true,
56            fresh: true,
57            // Deterministic battles: always hit, 89% variance, never crit.
58            rng_script: Some(vec![50, 100, 1]),
59            ..RunnerOptions::default()
60        },
61    )
62    .expect("boot game");
63
64    // The agenda per battle (index = battles started so far − 1).
65    let agendas: &[&[Pick]] = &[&[Pick::Item, Pick::Party, Pick::Fight], &[Pick::Fight]];
66    let mut battles_done = 0usize;
67    let mut agenda: Vec<Pick> = Vec::new();
68    // Queued button presses; one key every other frame (a held key is not a
69    // fresh just-press, so keys alternate with idle frames).
70    let mut keys: Vec<GbButton> = Vec::new();
71    let mut last_log: Vec<String> = Vec::new();
72    let mut snapped: Vec<String> = Vec::new();
73    let mut was_in_battle_prev = false;
74
75    let mut input = InputState::new();
76    for frame in 0..6000u32 {
77        let was_in_battle = was_in_battle_prev;
78
79        // Decide this frame's input.
80        let mut mask = 0;
81        if frame % 2 == 0 {
82            if !keys.is_empty() {
83                mask = keys.remove(0).bit_mask();
84            } else if let Some(battle) = game.battle() {
85                if battle.in_menu() {
86                    let items = battle.menu_items();
87                    let label = if items.first().is_some_and(|i| i == "Fight") {
88                        "root"
89                    } else if items.iter().any(|i| i.contains('/')) {
90                        "party"
91                    } else {
92                        "sub"
93                    };
94                    if let Some(dir) = &shot_dir {
95                        let tag = format!("battle{}-{label}", battles_done + 1);
96                        if !snapped.contains(&tag) {
97                            snapped.push(tag.clone());
98                            snap(&mut game, &dir.join(format!("{tag}.png")));
99                        }
100                    }
101                    mask = match label {
102                        "root" => {
103                            let pick = agenda.first().copied().unwrap_or(Pick::Fight);
104                            if !agenda.is_empty() {
105                                agenda.remove(0);
106                            }
107                            match pick {
108                                Pick::Fight => GbButton::A.bit_mask(),
109                                Pick::Party => {
110                                    keys.push(GbButton::A);
111                                    GbButton::Down.bit_mask()
112                                }
113                                Pick::Item => {
114                                    keys.push(GbButton::Down);
115                                    keys.push(GbButton::A);
116                                    GbButton::Down.bit_mask()
117                                }
118                            }
119                        }
120                        // Submenus: confirm the entry under the cursor (the
121                        // party cursor starts on the first switchable member).
122                        _ => GbButton::A.bit_mask(),
123                    };
124                } else if frame % 4 == 0 {
125                    mask = GbButton::A.bit_mask(); // page narration
126                }
127            } else if frame % 4 == 0 {
128                mask = GbButton::A.bit_mask(); // page dialogue
129            }
130        }
131        input.set_from_bitmask(mask);
132        game.update(&input);
133        input.begin_frame();
134
135        let in_battle = game.battle().is_some();
136        // Battle-start edge: print the party it starts with (the carried-over
137        // state from battle 2 on) and load its agenda.
138        if in_battle && !was_in_battle {
139            let n = battles_done + 1;
140            let battle = game.battle().unwrap();
141            println!("battle {n} starts:");
142            for c in battle.party() {
143                let status = c.status.as_deref().unwrap_or("-");
144                println!(
145                    "  {} {}/{} MP {}/{} status {}",
146                    c.name, c.hp, c.max_hp, c.mp, c.max_mp, status
147                );
148            }
149            println!("  inventory: {:?}", battle.inventory());
150            agenda = agendas[battles_done].to_vec();
151        }
152        if in_battle {
153            last_log = game.battle().unwrap().log().to_vec();
154        }
155        // Battle-end edge: the runner has harvested the party state.
156        if was_in_battle && !in_battle {
157            battles_done += 1;
158            println!("\nbattle {battles_done} log:");
159            for line in &last_log {
160                println!("  {line}");
161            }
162            if let Some(party) = game.party_state() {
163                println!("party state after battle {battles_done}:");
164                for m in party {
165                    println!("  {} hp {} mp {} status {:?}", m.id, m.hp, m.mp, m.status);
166                }
167            }
168            if let Some(inv) = game.inventory() {
169                println!("inventory: {inv:?}");
170            }
171            println!();
172            last_log.clear();
173            if battles_done == 2 {
174                println!("both battles done — stopping");
175                break;
176            }
177        }
178        was_in_battle_prev = in_battle;
179    }
180
181    if battles_done < 2 {
182        eprintln!("harness: only {battles_done} battle(s) completed within the frame cap");
183        std::process::exit(1);
184    }
185}
examples/encounter_accept.rs (line 53)
46fn main() {
47    let mut args = std::env::args().skip(1);
48    let dir = args
49        .next()
50        .expect("usage: encounter_accept <project-dir> [shot-dir]");
51    let shot_dir = args.next().map(PathBuf::from);
52
53    let project = LoadedProject::load(Path::new(&dir)).expect("load project");
54    let mut game = RunnerGame::new(
55        project,
56        RunnerOptions {
57            headless: true,
58            fresh: true,
59            // Deterministic battles: always hit, 89% variance, never crit.
60            rng_script: Some(vec![50, 100, 1]),
61            ..RunnerOptions::default()
62        },
63    )
64    .expect("boot game");
65    println!("money at boot: {}", game.money());
66
67    // The agenda per battle (index = battles started so far − 1): the
68    // trainer battle tries Run first (blocked), the wild battle runs.
69    // Battle 1's agenda is pre-armed: the entry scene suspends on
70    // `startBattle` during boot, so its first menu frame precedes the
71    // battle-start edge below (later battles arm on their edge — text plays
72    // between them).
73    let agendas: &[&[Pick]] = &[&[Pick::Run, Pick::Fight], &[Pick::Run]];
74    let mut battles_done = 0usize;
75    let mut agenda: Vec<Pick> = agendas[0].to_vec();
76    // Queued button presses; one key every other frame (a held key is not a
77    // fresh just-press, so keys alternate with idle frames).
78    let mut keys: Vec<GbButton> = Vec::new();
79    let mut last_log: Vec<String> = Vec::new();
80    let mut was_in_battle_prev = false;
81    let mut snapped: Vec<String> = Vec::new();
82    // Shop agenda: 0 = root (→ Sell), 1 = sell view (→ sell one), 2 = note
83    // (→ dismiss), 3 = back to root (→ B), 4 = exit (→ B), 5 = done.
84    let mut shop_step = 0usize;
85    let mut shop_done = false;
86
87    let mut input = InputState::new();
88    for frame in 0..6000u32 {
89        let was_in_battle = was_in_battle_prev;
90
91        // Decide this frame's input.
92        let mut mask = 0;
93        if frame % 2 == 0 {
94            if !keys.is_empty() {
95                mask = keys.remove(0).bit_mask();
96            } else if let Some(battle) = game.battle() {
97                if battle.in_menu() {
98                    let is_root = battle.menu_items().first().is_some_and(|i| i == "Fight");
99                    mask = if is_root {
100                        let pick = agenda.first().copied().unwrap_or(Pick::Fight);
101                        if !agenda.is_empty() {
102                            agenda.remove(0);
103                        }
104                        match pick {
105                            Pick::Fight => GbButton::A.bit_mask(),
106                            Pick::Run => {
107                                // Fight/Party/Item/Run → Down ×3, confirm.
108                                keys.push(GbButton::Down);
109                                keys.push(GbButton::Down);
110                                keys.push(GbButton::A);
111                                GbButton::Down.bit_mask()
112                            }
113                        }
114                    } else {
115                        GbButton::A.bit_mask() // skill submenu
116                    };
117                } else if frame % 4 == 0 {
118                    mask = GbButton::A.bit_mask(); // page narration
119                }
120            } else if game.shop_lines().is_some() && battles_done == 2 && !shop_done {
121                match shop_step {
122                    0 => {
123                        println!("shop root: {:?}", game.shop_lines().unwrap());
124                        keys.push(GbButton::Down); // → Sell
125                        keys.push(GbButton::A);
126                    }
127                    1 => {
128                        println!("sell view: {:?}", game.shop_lines().unwrap());
129                        keys.push(GbButton::A); // sell one Potion
130                    }
131                    2 => {
132                        let lines = game.shop_lines().unwrap();
133                        println!("sell note: {lines:?}");
134                        if let Some(dir) = &shot_dir {
135                            snap(&mut game, &dir.join("shop-sold.png"));
136                        }
137                        keys.push(GbButton::A); // dismiss the note
138                    }
139                    3 => keys.push(GbButton::B), // back to the root
140                    _ => keys.push(GbButton::B), // exit the shop
141                }
142                shop_step += 1;
143            } else if frame % 4 == 0 {
144                mask = GbButton::A.bit_mask(); // page dialogue
145            }
146        }
147        input.set_from_bitmask(mask);
148        game.update(&input);
149        input.begin_frame();
150
151        let in_battle = game.battle().is_some();
152        // Battle-start edge: print the matchup and load its agenda.
153        if in_battle && !was_in_battle {
154            let n = battles_done + 1;
155            let battle = game.battle().unwrap();
156            println!(
157                "battle {n} starts: {} vs {} (queued {}, trainer {}, reward {})",
158                battle.player().name,
159                battle.enemy().name,
160                battle.enemies_remaining(),
161                battle.is_trainer(),
162                battle.trainer_money(),
163            );
164            if battles_done > 0 {
165                agenda = agendas[battles_done].to_vec();
166            }
167        }
168        if in_battle {
169            // Screenshot the two v2-d narration lines on their first show.
170            // Screenshot the two v2-d narration lines on their first show.
171            let line = game
172                .battle()
173                .unwrap()
174                .current_line()
175                .map(str::to_string);
176            if let (Some(dir), Some(line)) = (&shot_dir, line) {
177                let tag = match line.as_str() {
178                    l if l.starts_with("Can't escape") => Some("run-blocked"),
179                    l if l.starts_with("Got away") => Some("run-safe"),
180                    l if l.starts_with("Got ") && l.ends_with("for winning!") => {
181                        Some("trainer-money")
182                    }
183                    _ => None,
184                };
185                if let Some(tag) = tag {
186                    if !snapped.contains(&tag.to_string()) {
187                        snapped.push(tag.to_string());
188                        snap(&mut game, &dir.join(format!("{tag}.png")));
189                    }
190                }
191            }
192            last_log = game.battle().unwrap().log().to_vec();
193        }
194        // Battle-end edge: the runner has harvested the state.
195        if was_in_battle && !in_battle {
196            battles_done += 1;
197            println!("\nbattle {battles_done} log:");
198            for line in &last_log {
199                println!("  {line}");
200            }
201            if battles_done == 1 {
202                assert!(
203                    last_log
204                        .iter()
205                        .any(|l| l == "Can't escape from a trainer battle!"),
206                    "the trainer Run attempt must be blocked (and the turn not consumed)"
207                );
208            }
209            println!("money after battle {battles_done}: {}", game.money());
210            if let Some(party) = game.party_state() {
211                for m in party {
212                    println!(
213                        "  {} hp {} mp {} level {} exp {}",
214                        m.id, m.hp, m.mp, m.level, m.exp
215                    );
216                }
217            }
218            println!();
219            last_log.clear();
220        }
221        // Shop-exit edge.
222        if shop_step >= 5 && game.shop_lines().is_none() && !shop_done {
223            shop_done = true;
224            println!("shop closed: money {}, inventory {:?}", game.money(), game.inventory());
225        }
226        // Everything done: both battles + the shop, scene finished.
227        if battles_done == 2 && shop_done && game.battle().is_none() {
228            println!("acceptance complete");
229            break;
230        }
231        was_in_battle_prev = in_battle;
232    }
233
234    // Verify the v2-d contract points and exit non-zero on any miss.
235    let money = game.money();
236    let potions = game.inventory().and_then(|inv| inv.get("potion").copied());
237    println!("final: money {money}, potions {potions:?}");
238    assert_eq!(battles_done, 2, "both battles must complete");
239    assert!(shop_done, "the shop sell must complete");
240    assert_eq!(money, 142, "100 start + 32 trainer + 10 sell (20/2)");
241    assert_eq!(potions, Some(2), "3 starting − 1 sold");
242}
Source

pub fn load_with_files(files: Arc<dyn ProjectFiles>) -> Result<Self>

Load the project from a ProjectFiles backend.

The DSL is compiled in memory; any compiler diagnostic (unreadable file, compile failure, route conflict) aborts the load with an error listing every diagnostic — the same bar dotzuki check enforces.

§Errors

Fails on a missing/unparseable manifest or any DSL diagnostic.

Source

pub fn recompile_scripts(&mut self) -> Result<()>

Recompile every DSL directory and swap the compiled scenes in place.

On success the script registry, routing table and stem indexes are replaced wholesale — a scene currently mid-activation keeps running the JS it was started with; the next activation picks up the new source. On any compiler diagnostic the old scenes are kept and an error listing every diagnostic is returned (same bar as load).

§Errors

Fails when the recompile produces any diagnostic.

Source

pub fn files(&self) -> &Arc<dyn ProjectFiles>

The project’s file backend.

Source

pub fn root(&self) -> &Path

Project root directory (empty for a project without a disk root).

Source

pub fn manifest(&self) -> &Manifest

The parsed .dotzuki-editor.json manifest.

Source

pub fn data_root(&self) -> &Path

Resolved data root (manifest dataRoot against the project root).

Source

pub fn data_root_rel(&self) -> &str

The data root as a project-relative POSIX path (VFS key prefix).

Source

pub fn gfx_root(&self) -> Option<&Path>

Resolved graphics root (manifest gfxRoot), when configured.

Source

pub fn gfx_root_rel(&self) -> String

The graphics root as a project-relative POSIX path (the manifest’s gfxRoot, default "gfx").

Source

pub fn scripts(&self) -> &ScriptLoader

Registry of compiled scene JS, keyed by scene name.

Source

pub fn report(&self) -> &CompileReport

The full DSL compile report.

Source

pub fn routes(&self) -> &[RouteEntry]

Storyline routing table (map, npc/onEnter) → storyline, collected from @trigger declarations across all scenes.

Source

pub fn scene_name_for_stem(&self, stem: &str) -> Option<&str>

Compiled scene name for a .scene file stem (e.g. "main""Main").

Source

pub fn stem_for_scene_name(&self, name: &str) -> Option<&str>

.scene file stem for a compiled scene name.

Source

pub fn maps_dir_rel(&self) -> String

The maps directory as a project-relative POSIX path: the map activity’s mapsDir (dataRoot-relative), default maps.

Source

pub fn maps_dir(&self) -> PathBuf

Directory holding the per-map subdirectories (disk form of maps_dir_rel).

Source

pub fn map_ids(&self) -> Vec<String>

Sorted ids of all map directories under maps_dir.

Source

pub fn entry_map(&self) -> Result<String>

Map to spawn on: game.entryMap, or the first map directory (sorted) under the maps dir.

§Errors

Fails when no entryMap is configured and no map directories exist.

Source

pub fn entry_scene_name(&self) -> Result<&str>

Scene to boot into: game.entryScene (a .scene file stem) resolved to its compiled scene name, or the first compiled scene sorted by source path.

§Errors

Fails when entryScene names a stem that compiled to nothing, or when the project has no scenes at all.

Source

pub fn load_map(&self, map_id: &str) -> Result<RuntimeMap>

Load a map by id from this project’s maps dir.

Source

pub fn table_dir(&self, table_id: &str) -> Option<PathBuf>

Directory holding the records of data table table_id (a table id from the data activity’s config.tables[]), resolved against the project root. None when the id names no declared table.

Source

pub fn table_dir_rel(&self, table_id: &str) -> Option<String>

The record directory of data table table_id as a project-relative POSIX path (the VFS form of table_dir). None when the id names no declared table.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> Conv for T

Source§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> FmtForward for T

Source§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
Source§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
Source§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
Source§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
Source§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
Source§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
Source§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
Source§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
Source§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> MaybeSendSync for T

Source§

impl<D> OwoColorize for D

Source§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where C: Color,

Set the foreground color generically Read more
Source§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where C: Color,

Set the background color generically. Read more
Source§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
Source§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
Source§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
Source§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
Source§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
Source§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
Source§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
Source§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
Source§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
Source§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
Source§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
Source§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
Source§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
Source§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
Source§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
Source§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
Source§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
Source§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
Source§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
Source§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
Source§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
Source§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
Source§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
Source§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
Source§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
Source§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
Source§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
Source§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
Source§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
Source§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
Source§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
Source§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
Source§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
Source§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
Source§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
Source§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
Source§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
Source§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
Source§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
Source§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
Source§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
Source§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text underlined
Make the text blink
Make the text blink (but fast!)
Source§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
Source§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
Source§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
Source§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at compile-time. If the color is constant, use either OwoColorize::fg or a color-specific method, such as OwoColorize::green, Read more
Source§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at compile-time. If the color is constant, use either OwoColorize::bg or a color-specific method, such as OwoColorize::on_yellow, Read more
Source§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( &self, ) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
Source§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( &self, ) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
Source§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
Source§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
Source§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
Source§

impl<T> Pipe for T
where T: ?Sized,

Source§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
Source§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
Source§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Source§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
Source§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
Source§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
Source§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Tap for T

Source§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
Source§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
Source§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
Source§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
Source§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
Source§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
Source§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
Source§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
Source§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
Source§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T> TryConv for T

Source§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more