Skip to main content

dotzuki_engine_script/
api_registrar.rs

1//! ScriptApiRegistrar trait — enables game-agnostic JS API registration.
2//!
3//! The core engine registers generic APIs (showText, moveNpc, getFlag, warpTo, etc.)
4//! on the `game` global object. Game-specific APIs (giveMonster, startBattle, etc.)
5//! are registered by implementors of this trait via `ScriptEngine::with_api()`.
6//!
7//! DSL scene management APIs (showScene, hideScene, updateUI) are registered as
8//! core APIs during `ScriptEngine::new()`.
9
10use crate::command::ScriptCommand;
11use crate::engine::ScriptEngine;
12use boa_engine::JsArgs;
13
14/// Trait for registering game-specific JavaScript APIs.
15///
16/// Implementations add function properties to the `game` global JS object
17/// (already created by the core engine) during `ScriptEngine` initialization.
18///
19/// # Example
20///
21/// ```ignore
22/// struct MyGameApi;
23/// impl ScriptApiRegistrar for MyGameApi {
24///     fn register_api(&self, engine: &mut ScriptEngine) {
25///         engine.register_async_fn("myCommand", |args, ctx| {
26///             // ... build ScriptCommand ...
27///         });
28///     }
29/// }
30///
31/// let engine = ScriptEngine::with_api(&MyGameApi);
32/// ```
33pub trait ScriptApiRegistrar {
34    /// Register functions on the `game` JS object.
35    /// Called during `ScriptEngine` initialization, after core APIs
36    /// have been registered and the `game` global object is available.
37    fn register_api(&self, engine: &mut ScriptEngine);
38}
39
40/// Register the `game.showScene()` JS API on the given engine.
41///
42/// Callable from JS as: `await game.showScene("shop")`
43/// Produces `ScriptCommand::ShowScene { scene_name, layout_json: None }`.
44pub fn register_show_scene(engine: &mut ScriptEngine) {
45    engine.register_async_fn("showScene", |args, ctx| {
46        let scene_name = args
47            .get_or_undefined(0)
48            .to_string(ctx)?
49            .to_std_string_lossy();
50        Ok(ScriptCommand::ShowScene {
51            scene_name,
52            layout_json: None,
53        })
54    });
55}
56
57/// Register the `game.hideScene()` JS API on the given engine.
58///
59/// Callable from JS as: `await game.hideScene("shop")`
60/// Produces `ScriptCommand::HideScene { scene_name }`.
61pub fn register_hide_scene(engine: &mut ScriptEngine) {
62    engine.register_async_fn("hideScene", |args, ctx| {
63        let scene_name = args
64            .get_or_undefined(0)
65            .to_string(ctx)?
66            .to_std_string_lossy();
67        Ok(ScriptCommand::HideScene { scene_name })
68    });
69}
70
71/// Register the `game.updateUI()` JS API on the given engine.
72///
73/// Callable from JS as: `await game.updateUI("shop", { gold: 999 })`
74/// The `data` argument is serialized via `JSON.stringify` by the Boa runtime.
75/// Produces `ScriptCommand::UpdateUI { scene_name, data_json }`.
76pub fn register_update_ui(engine: &mut ScriptEngine) {
77    engine.register_async_fn("updateUI", |args, ctx| {
78        let scene_name = args
79            .get_or_undefined(0)
80            .to_string(ctx)?
81            .to_std_string_lossy();
82        let data_val = args.get_or_undefined(1);
83        let json_val = data_val.to_json(ctx)?;
84        let data_json = json_val.to_string();
85        Ok(ScriptCommand::UpdateUI {
86            scene_name,
87            data_json,
88        })
89    });
90}