9eead719b0
Full project snapshot migrated to new Gitea remote without history: engine, editor, physics, script, examples, tests, docs, and assets. Relicensed from GPLv3 to MIT and updated repo URLs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
83 lines
2.8 KiB
Rust
83 lines
2.8 KiB
Rust
//! The [`ScriptModule`] — the Stage-10 entry point that wires scripting into an
|
|
//! [`App`].
|
|
//!
|
|
//! Following the engine's module convention, everything the scripting layer
|
|
//! contributes is registered here so it can be enabled, disabled, or removed as
|
|
//! a unit (and so an exported game that uses no scripts never compiles them in).
|
|
//! This first piece registers the [`Script`] component *type* for reflection
|
|
//! (making it dual-editable and captured by the play-mode snapshot), installs
|
|
//! the `.rhai` [`ScriptLoader`], and inserts the shared [`ScriptEngine`]. The
|
|
//! lifecycle system that compiles and runs scripts each frame is added in a
|
|
//! later piece.
|
|
|
|
use oxide_engine::app::{App, Module, Schedule};
|
|
|
|
use crate::host::run_scripts;
|
|
use crate::{Script, ScriptHost, ScriptLoader};
|
|
|
|
/// The scripting module. Add it after [`DefaultModules`] to give an app a
|
|
/// `rhai`-backed scripting layer.
|
|
///
|
|
/// [`DefaultModules`]: oxide_engine::app::DefaultModules
|
|
///
|
|
/// ```
|
|
/// use oxide_engine::app::App;
|
|
/// use oxide_script::ScriptModule;
|
|
///
|
|
/// let mut app = App::new();
|
|
/// app.add_module(ScriptModule);
|
|
/// assert!(app.has_module("script"));
|
|
/// assert!(app.types.is_registered("Script"));
|
|
/// ```
|
|
pub struct ScriptModule;
|
|
|
|
impl Module for ScriptModule {
|
|
fn name(&self) -> &'static str {
|
|
"script"
|
|
}
|
|
|
|
fn build(&self, app: &mut App) {
|
|
// Register the component type for reflection so it round-trips through
|
|
// RON (scripts/AI/inspector) and is captured by the play-mode snapshot.
|
|
app.register_type::<Script>("Script");
|
|
|
|
// Teach the asset server to load `.rhai` files as `ScriptAsset`s.
|
|
app.add_loader(ScriptLoader);
|
|
|
|
// The runtime that compiles and runs each entity's script, driven on
|
|
// `Update` (after `FixedUpdate`, so scripts observe post-physics poses).
|
|
app.insert_resource(ScriptHost::new());
|
|
app.add_system(Schedule::Update, run_scripts);
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use oxide_engine::app::DefaultModules;
|
|
|
|
#[test]
|
|
fn module_registers_its_type_loader_and_host() {
|
|
let mut app = App::new();
|
|
app.add_modules(DefaultModules);
|
|
app.add_module(ScriptModule);
|
|
|
|
assert!(app.has_module("script"));
|
|
assert!(app.types.is_registered("Script"));
|
|
assert!(app.has_resource::<ScriptHost>());
|
|
// The per-frame run_scripts system was registered.
|
|
assert!(app.system_count() >= 1);
|
|
}
|
|
|
|
#[test]
|
|
fn removing_the_module_drops_its_type() {
|
|
let mut app = App::new();
|
|
app.add_module(ScriptModule);
|
|
assert!(app.types.is_registered("Script"));
|
|
|
|
assert!(app.remove_module("script"));
|
|
assert!(!app.has_module("script"));
|
|
assert!(!app.types.is_registered("Script"));
|
|
}
|
|
}
|