pub struct ScriptRuntime { /* private fields */ }Expand description
Compiles and caches one [AST] per unique script path (shared across every entity that
attaches the same script) and owns each (entity, attachment index)’s running Rhai Scope.
Created when the editor’s Play mode starts and dropped when it stops — nothing here is meant
to survive a Stop; see the implementation plan’s “Play/Stop snapshot” note for why script
state resetting on Stop is load-bearing, not just convenient.
Implementations§
Source§impl ScriptRuntime
impl ScriptRuntime
pub fn new(project_root: PathBuf) -> Self
Sourcepub fn begin_frame(&mut self, world: &World)
pub fn begin_frame(&mut self, world: &World)
Refreshes the [FrameSnapshot] every world.find(...) call this frame will read from.
Call once per frame, before running any script that frame (see the editor’s
EditorScene::update, EditorMode::Playing branch).
Sourcepub fn start_script(
&mut self,
world: &mut World,
entity: Entity,
index: usize,
script_path: &Path,
renderer: Option<&Renderer<'_>>,
) -> Vec<ScriptError>
pub fn start_script( &mut self, world: &mut World, entity: Entity, index: usize, script_path: &Path, renderer: Option<&Renderer<'_>>, ) -> Vec<ScriptError>
Compiles (or reuses the cached [AST] for) the script at script_path, then starts a
fresh instance of it for (entity, index): runs the script body once — which defines its
top-level locals and on_start/on_update closures — and calls on_start() if the
script defined one. world supplies the entity’s starting position/name so on_start
sees real data rather than a zeroed placeholder, and (now that it’s &mut) lets this
method drain whatever on_start queues via entity/world/scene immediately rather
than leaving it pending — a script whose only hook is on_start (no on_update ever
runs to drain the shared queue on its behalf) would otherwise have calls like
entity.set_persistent(true) or scene.change(...) sit in the queue forever. renderer
is threaded through to that drain for the same reason Self::drain_commands needs one
(entity.set_sprite/set_model).
A compile/read/body error is fatal — no instance is created and the single resulting
error is returned. An on_start error is not: the instance is still created (so
on_update still runs on later frames) and the error is only reported, not propagated as
a failure to start. Every error encountered (compile/read/body, on_start itself, or
anything the drain surfaces) is returned rather than the first one short-circuiting,
mirroring Self::update_entity’s own error-collection shape.
Sourcepub fn start_all_scripts(
&mut self,
world: &mut World,
base_dir: &Path,
renderer: Option<&Renderer<'_>>,
) -> Vec<ScriptError>
pub fn start_all_scripts( &mut self, world: &mut World, base_dir: &Path, renderer: Option<&Renderer<'_>>, ) -> Vec<ScriptError>
Starts every enabled script attachment (in attachment order) that isn’t already running on
an entity currently in world — the “start scripts” half of loading a scene, factored out
so EditorScene::start_play, runtime’s RuntimeScene::start, and a script-triggered
scene.change(...) (see [WorldCommand::ChangeScene]) all run it identically instead of
each keeping its own copy of this loop. The “isn’t already running” check is what lets a
scene change call this over the whole post-change world (persistent entities included)
without restarting a persistent entity’s already-running script and losing its state.
base_dir resolves each attachment’s project-relative path into a real file path (an
editor project’s root, or an exported game’s res/ directory). Caller must call
Self::begin_frame first so world.find(...) inside any on_start sees a snapshot that
includes the entities being started (see
runtime_tests::on_start_can_read_other_entities_via_find_when_begin_frame_ran_first).
renderer is forwarded to each Self::start_script call, for the same reason
Self::drain_commands needs one (an on_start that calls entity.set_sprite/
set_model).
Sourcepub fn update_entity(
&mut self,
world: &mut World,
entity: Entity,
dt: f32,
input: &InputState,
mouse: &MouseState,
mouse_delta: (f32, f32),
renderer: Option<&Renderer<'_>>,
) -> Vec<ScriptError>
pub fn update_entity( &mut self, world: &mut World, entity: Entity, dt: f32, input: &InputState, mouse: &MouseState, mouse_delta: (f32, f32), renderer: Option<&Renderer<'_>>, ) -> Vec<ScriptError>
Calls every started, enabled attachment’s on_update(dt, input) closure for entity, in
attachment order (disabled attachments — including ones this call itself just disabled
after too many failures — are skipped), syncing the entity’s crate::world::Transform
and name in beforehand and applying whatever it queued via entity/world (see
Self::drain_commands) right after. One instance erroring doesn’t stop the others;
every error encountered is returned rather than the first one short-circuiting. If an
attachment despawns its own entity, the remaining attachments on that entity are skipped
for the rest of this call — there’s nothing left to update.
renderer is only needed for entity.set_sprite(...)/set_model(...) (loading a new
asset needs a live GPU device); pass None when one isn’t available (e.g. in a test with
no real Renderer) and any such command just reports a ScriptError instead of
silently doing nothing or panicking.
mouse_delta is the caller’s responsibility, same as it is for
editor::fly_camera::FlyCamera::update — MouseState only tracks position, not
frame-to-frame movement, so the caller (which already diffs MouseState::position()
against last frame’s for its own fly camera) passes it through directly.
Auto Trait Implementations§
impl !Freeze for ScriptRuntime
impl !RefUnwindSafe for ScriptRuntime
impl !Send for ScriptRuntime
impl !Sync for ScriptRuntime
impl !UnwindSafe for ScriptRuntime
impl Unpin for ScriptRuntime
impl UnsafeUnpin for ScriptRuntime
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
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.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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