improved script api to support errors

This commit is contained in:
Dmitry Stepanov
2025-12-23 21:32:50 +03:00
parent 6b63915c41
commit 833cc35c31
4 changed files with 218 additions and 87 deletions
+119 -63
View File
@@ -31,10 +31,6 @@ pub mod task;
mod hotreload;
mod wasm_utils;
use crate::engine::input::InputState;
use crate::renderer::ui_renderer::UiRenderInfo;
use crate::resource::gltf::material::GLTF_SHADER;
use crate::scene::skybox::SkyBoxKind;
use crate::{
asset::{
event::ResourceEvent,
@@ -44,6 +40,7 @@ use crate::{
},
core::{
algebra::Vector2,
err,
futures::{executor::block_on, future::join_all},
instant,
log::Log,
@@ -51,18 +48,21 @@ use crate::{
reflect::Reflect,
task::TaskPool,
variable::try_inherit_properties,
SafeLock,
visitor::error::VisitError,
warn, SafeLock,
},
engine::{error::EngineError, task::TaskPoolHandler},
engine::{error::EngineError, input::InputState, task::TaskPoolHandler},
event::Event,
graph::{BaseSceneGraph, NodeMapping, SceneGraph},
graphics::error::FrameworkError,
gui::{
constructor::WidgetConstructorContainer,
font::{loader::FontLoader, Font, BUILT_IN_FONT},
font::{
loader::FontLoader, Font, BOLD_ITALIC, BUILT_IN_BOLD, BUILT_IN_FONT, BUILT_IN_ITALIC,
},
loader::UserInterfaceLoader,
style::{self, resource::StyleLoader, Style},
UiContainer, UiUpdateSwitches, UserInterface,
RenderMode, UiContainer, UiUpdateSwitches, UserInterface,
},
material::{
self,
@@ -74,9 +74,10 @@ use crate::{
dylib::DyLibDynamicPlugin, DynamicPlugin, Plugin, PluginContainer, PluginContext,
PluginRegistrationContext,
},
renderer::Renderer,
renderer::{ui_renderer::UiRenderInfo, Renderer},
resource::{
curve::{loader::CurveLoader, CurveResourceState},
gltf::material::GLTF_SHADER,
model::{loader::ModelLoader, Model, ModelResource},
texture::{
self, loader::TextureLoader, CompressionOptions, Texture, TextureImportOptions,
@@ -92,6 +93,7 @@ use crate::{
constructor::{new_node_constructor_container, NodeConstructorContainer},
Node,
},
skybox::SkyBoxKind,
sound::SoundEngine,
tilemap::{
brush::{TileMapBrush, TileMapBrushLoader},
@@ -100,6 +102,7 @@ use crate::{
},
Scene, SceneContainer, SceneLoader,
},
script::ScriptResult,
script::{
constructor::ScriptConstructorContainer, DynamicTypeId, PluginsRefMut, RoutingStrategy,
Script, ScriptContext, ScriptDeinitContext, ScriptMessage, ScriptMessageContext,
@@ -109,16 +112,12 @@ use crate::{
};
use fxhash::{FxHashMap, FxHashSet};
use fyrox_animation::AnimationTracksData;
use fyrox_core::visitor::error::VisitError;
use fyrox_core::warn;
use fyrox_graphics::server::SharedGraphicsServer;
use fyrox_graphics_gl::server::GlGraphicsServer;
use fyrox_sound::{
buffer::{loader::SoundBufferLoader, SoundBuffer},
renderer::hrtf::{HrirSphereLoader, HrirSphereResourceData},
};
use fyrox_ui::font::{BOLD_ITALIC, BUILT_IN_BOLD, BUILT_IN_ITALIC};
use fyrox_ui::RenderMode;
use std::{
any::TypeId,
cell::Cell,
@@ -634,7 +633,7 @@ impl ScriptMessageDispatcher {
input_state,
};
process_node_scripts(&mut context, &mut |s, ctx| {
process_node_scripts("on_message", &mut context, &mut |s, ctx| {
s.on_message(&mut *payload, ctx)
})
}
@@ -662,9 +661,11 @@ impl ScriptMessageDispatcher {
};
if receivers.contains(&node) {
process_node_scripts(&mut context, &mut |s, ctx| {
s.on_message(&mut *payload, ctx)
});
process_node_scripts(
"on_message",
&mut context,
&mut |s, ctx| s.on_message(&mut *payload, ctx),
);
}
node = parent;
@@ -689,9 +690,11 @@ impl ScriptMessageDispatcher {
};
if receivers.contains(&node) {
process_node_scripts(&mut context, &mut |s, ctx| {
s.on_message(&mut *payload, ctx)
});
process_node_scripts(
"on_message",
&mut context,
&mut |s, ctx| s.on_message(&mut *payload, ctx),
);
}
}
}
@@ -714,7 +717,7 @@ impl ScriptMessageDispatcher {
input_state,
};
process_node_scripts(&mut context, &mut |s, ctx| {
process_node_scripts("on_message", &mut context, &mut |s, ctx| {
s.on_message(&mut *payload, ctx)
});
}
@@ -864,16 +867,19 @@ impl ScriptProcessor {
context.script_index = script_index;
process_node_script(
"on_init",
script_index,
&mut context,
&mut |script, context| {
if !script.initialized {
script.on_init(context);
script.on_init(context)?;
script.initialized = true;
}
// `on_start` must be called even if the script was initialized.
start_queue.push_back((handle, script_index));
Ok(())
},
);
}
@@ -900,14 +906,17 @@ impl ScriptProcessor {
context.script_index = script_index;
process_node_script(
"on_start",
script_index,
&mut context,
&mut |script, context| {
if script.initialized && !script.started {
script.on_start(context);
let result = script.on_start(context);
script.started = true;
update_queue.push_back((handle, script_index));
result
} else {
Ok(())
}
},
);
@@ -930,9 +939,12 @@ impl ScriptProcessor {
context.handle = handle;
context.script_index = script_index;
process_node_script(script_index, &mut context, &mut |script, context| {
script.on_update(context);
});
process_node_script(
"on_update",
script_index,
&mut context,
&mut |script, context| script.on_update(context),
);
}
}
@@ -986,7 +998,9 @@ impl ScriptProcessor {
// `on_deinit` could also spawn new nodes, but we won't take those into account on
// this frame. They'll be correctly handled on next frame.
script.on_deinit(&mut context);
if let Err(error) = script.on_deinit(&mut context) {
err!("An error occurred during on_deinit call. Reason: {error}");
}
}
}
@@ -1013,9 +1027,11 @@ impl ScriptProcessor {
let handle_node = context.scene.graph.handle_from_index(node_index);
context.node_handle = handle_node;
process_node_scripts(&mut context, &mut |script, context| {
process_node_scripts("on_deinit", &mut context, &mut |script, context| {
if script.initialized {
script.on_deinit(context)
} else {
Ok(())
}
});
}
@@ -1183,9 +1199,9 @@ pub struct EngineInitParams {
pub task_pool: Arc<TaskPool>,
}
fn process_node_script<T, C>(index: usize, context: &mut C, func: &mut T) -> bool
fn process_node_script<T, C>(caller_name: &str, index: usize, context: &mut C, func: &mut T) -> bool
where
T: FnMut(&mut Script, &mut C),
T: FnMut(&mut Script, &mut C) -> ScriptResult,
C: UniversalScriptContext,
{
let Ok(node) = context.node() else {
@@ -1206,7 +1222,9 @@ where
return false;
};
func(&mut script, context);
if let Err(error) = func(&mut script, context) {
err!("An error occurred during {caller_name} call. Reason: {error}");
}
match context.node() {
Ok(node) => {
@@ -1232,16 +1250,16 @@ where
true
}
fn process_node_scripts<T, C>(context: &mut C, func: &mut T)
fn process_node_scripts<T, C>(caller_name: &str, context: &mut C, func: &mut T)
where
T: FnMut(&mut Script, &mut C),
T: FnMut(&mut Script, &mut C) -> ScriptResult,
C: UniversalScriptContext,
{
let mut index = 0;
loop {
context.set_script_index(index);
if !process_node_script(index, context, func) {
if !process_node_script(caller_name, index, context, func) {
return;
}
@@ -1251,6 +1269,7 @@ where
}
pub(crate) fn process_scripts<T>(
caller_name: &str,
scene: &mut Scene,
scene_handle: Handle<Scene>,
plugins: &mut [PluginContainer],
@@ -1265,7 +1284,7 @@ pub(crate) fn process_scripts<T>(
input_state: &InputState,
mut func: T,
) where
T: FnMut(&mut Script, &mut ScriptContext),
T: FnMut(&mut Script, &mut ScriptContext) -> ScriptResult,
{
let mut context = ScriptContext {
dt,
@@ -1287,7 +1306,7 @@ pub(crate) fn process_scripts<T>(
for node_index in 0..context.scene.graph.capacity() {
context.handle = context.scene.graph.handle_from_index(node_index);
process_node_scripts(&mut context, &mut func);
process_node_scripts(caller_name, &mut context, &mut func);
}
}
@@ -2407,6 +2426,7 @@ impl Engine {
let scene = &mut self.scenes[scene_handle];
if *scene.enabled {
process_scripts(
"on_os_event",
scene,
scene_handle,
&mut self.plugins,
@@ -2421,7 +2441,9 @@ impl Engine {
&self.input_state,
|script, context| {
if script.initialized && script.started {
script.on_os_event(event, context);
script.on_os_event(event, context)
} else {
Ok(())
}
},
)
@@ -2932,6 +2954,7 @@ impl Drop for Engine {
#[cfg(test)]
mod test {
use crate::engine::ApplicationLoopController;
use crate::script::ScriptResult;
use crate::{
asset::manager::ResourceManager,
core::{
@@ -3003,7 +3026,7 @@ mod test {
}
impl ScriptTrait for MyScript {
fn on_init(&mut self, ctx: &mut ScriptContext) {
fn on_init(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
self.sender
.send(Event::Initialized(Source::from_ctx(ctx)))
.unwrap();
@@ -3014,9 +3037,11 @@ mod test {
}))
.build(&mut ctx.scene.graph);
assert_eq!(handle, Handle::new(2, 1));
Ok(())
}
fn on_start(&mut self, ctx: &mut ScriptContext) {
fn on_start(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
self.sender
.send(Event::Started(Source::from_ctx(ctx)))
.unwrap();
@@ -3027,15 +3052,19 @@ mod test {
}))
.build(&mut ctx.scene.graph);
assert_eq!(handle, Handle::new(3, 1));
Ok(())
}
fn on_deinit(&mut self, ctx: &mut ScriptDeinitContext) {
fn on_deinit(&mut self, ctx: &mut ScriptDeinitContext) -> ScriptResult {
self.sender
.send(Event::Destroyed(Source::from_deinit_ctx(ctx)))
.unwrap();
Ok(())
}
fn on_update(&mut self, ctx: &mut ScriptContext) {
fn on_update(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
self.sender
.send(Event::Updated(Source::from_ctx(ctx)))
.unwrap();
@@ -3049,6 +3078,8 @@ mod test {
self.spawned = true;
}
Ok(())
}
}
@@ -3061,28 +3092,32 @@ mod test {
}
impl ScriptTrait for MySubScript {
fn on_init(&mut self, ctx: &mut ScriptContext) {
fn on_init(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
self.sender
.send(Event::Initialized(Source::from_ctx(ctx)))
.unwrap();
Ok(())
}
fn on_start(&mut self, ctx: &mut ScriptContext) {
fn on_start(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
self.sender
.send(Event::Started(Source::from_ctx(ctx)))
.unwrap();
Ok(())
}
fn on_deinit(&mut self, ctx: &mut ScriptDeinitContext) {
fn on_deinit(&mut self, ctx: &mut ScriptDeinitContext) -> ScriptResult {
self.sender
.send(Event::Destroyed(Source::from_deinit_ctx(ctx)))
.unwrap();
Ok(())
}
fn on_update(&mut self, ctx: &mut ScriptContext) {
fn on_update(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
self.sender
.send(Event::Updated(Source::from_ctx(ctx)))
.unwrap();
Ok(())
}
}
@@ -3215,15 +3250,16 @@ mod test {
}
impl ScriptTrait for ScriptListeningToMessages {
fn on_start(&mut self, ctx: &mut ScriptContext) {
fn on_start(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
ctx.message_dispatcher.subscribe_to::<MyMessage>(ctx.handle);
Ok(())
}
fn on_message(
&mut self,
message: &mut dyn ScriptMessagePayload,
ctx: &mut ScriptMessageContext,
) {
) -> ScriptResult {
let typed_message = message.downcast_ref::<MyMessage>().unwrap();
match self.index {
0 => {
@@ -3250,6 +3286,8 @@ mod test {
}
self.index += 1;
Ok(())
}
}
@@ -3260,7 +3298,7 @@ mod test {
}
impl ScriptTrait for ScriptSendingMessages {
fn on_update(&mut self, ctx: &mut ScriptContext) {
fn on_update(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
match self.index {
0 => ctx.message_sender.send_global(MyMessage::Foo(123)),
1 => ctx
@@ -3269,6 +3307,8 @@ mod test {
_ => (),
}
self.index += 1;
Ok(())
}
}
@@ -3345,7 +3385,7 @@ mod test {
}
impl ScriptTrait for ScriptSpawningAsyncTasks {
fn on_start(&mut self, ctx: &mut ScriptContext) {
fn on_start(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
ctx.task_pool.spawn_script_task(
ctx.scene_handle,
ctx.handle,
@@ -3355,7 +3395,8 @@ mod test {
assert_eq!(result, 123u32);
script.num = Some(result);
},
)
);
Ok(())
}
}
@@ -3444,31 +3485,35 @@ mod test {
}
impl ScriptTrait for ScriptThatDeletesItself {
fn on_init(&mut self, ctx: &mut ScriptContext) {
fn on_init(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
self.sender
.send(Event::Initialized(Source::from_ctx(ctx)))
.unwrap();
Ok(())
}
fn on_start(&mut self, ctx: &mut ScriptContext) {
fn on_start(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
self.sender
.send(Event::Started(Source::from_ctx(ctx)))
.unwrap();
Ok(())
}
fn on_deinit(&mut self, ctx: &mut ScriptDeinitContext) {
fn on_deinit(&mut self, ctx: &mut ScriptDeinitContext) -> ScriptResult {
self.sender
.send(Event::Destroyed(Source::from_deinit_ctx(ctx)))
.unwrap();
Ok(())
}
fn on_update(&mut self, ctx: &mut ScriptContext) {
fn on_update(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
self.sender
.send(Event::Updated(Source::from_ctx(ctx)))
.unwrap();
let node = &mut ctx.scene.graph[ctx.handle];
node.remove_script(ctx.script_index);
Ok(())
}
}
@@ -3482,13 +3527,14 @@ mod test {
}
impl ScriptTrait for ScriptThatAddsScripts {
fn on_init(&mut self, ctx: &mut ScriptContext) {
fn on_init(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
self.sender
.send(Event::Initialized(Source::from_ctx(ctx)))
.unwrap();
Ok(())
}
fn on_start(&mut self, ctx: &mut ScriptContext) {
fn on_start(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
self.sender
.send(Event::Started(Source::from_ctx(ctx)))
.unwrap();
@@ -3499,18 +3545,24 @@ mod test {
sender: self.sender.clone(),
});
}
Ok(())
}
fn on_deinit(&mut self, ctx: &mut ScriptDeinitContext) {
fn on_deinit(&mut self, ctx: &mut ScriptDeinitContext) -> ScriptResult {
self.sender
.send(Event::Destroyed(Source::from_deinit_ctx(ctx)))
.unwrap();
Ok(())
}
fn on_update(&mut self, ctx: &mut ScriptContext) {
fn on_update(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
self.sender
.send(Event::Updated(Source::from_ctx(ctx)))
.unwrap();
Ok(())
}
}
@@ -3524,28 +3576,32 @@ mod test {
}
impl ScriptTrait for SimpleScript {
fn on_init(&mut self, ctx: &mut ScriptContext) {
fn on_init(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
self.sender
.send(Event::Initialized(Source::from_ctx(ctx)))
.unwrap();
Ok(())
}
fn on_start(&mut self, ctx: &mut ScriptContext) {
fn on_start(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
self.sender
.send(Event::Started(Source::from_ctx(ctx)))
.unwrap();
Ok(())
}
fn on_deinit(&mut self, ctx: &mut ScriptDeinitContext) {
fn on_deinit(&mut self, ctx: &mut ScriptDeinitContext) -> ScriptResult {
self.sender
.send(Event::Destroyed(Source::from_deinit_ctx(ctx)))
.unwrap();
Ok(())
}
fn on_update(&mut self, ctx: &mut ScriptContext) {
fn on_update(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
self.sender
.send(Event::Updated(Source::from_ctx(ctx)))
.unwrap();
Ok(())
}
}
+3 -1
View File
@@ -176,6 +176,7 @@ impl TaskPoolHandler {
/// # script::{ScriptContext, ScriptTrait},
/// # };
/// # use fyrox_core::uuid_provider;
/// # use fyrox_impl::script::ScriptResult;
/// #
/// #[derive(Reflect, Visit, Default, Debug, Clone)]
/// struct MyScript;
@@ -184,7 +185,7 @@ impl TaskPoolHandler {
/// # uuid_provider!(MyScript = "f5ded79e-6101-4e23-b20d-48cbdb25d87a");
///
/// impl ScriptTrait for MyScript {
/// fn on_start(&mut self, ctx: &mut ScriptContext) {
/// fn on_start(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
/// ctx.task_pool.spawn_script_task(
/// ctx.scene_handle,
/// ctx.handle,
@@ -204,6 +205,7 @@ impl TaskPoolHandler {
/// }
/// },
/// );
/// Ok(())
/// }
/// }
/// ```
+87 -20
View File
@@ -22,35 +22,33 @@
//! Script is used to add custom logic to scene nodes. See [ScriptTrait] for more info.
use crate::engine::input::InputState;
use crate::{
asset::manager::ResourceManager,
core::{
log::Log,
pool::Handle,
reflect::{FieldRef, Reflect, ReflectArray, ReflectList},
pool::{Handle, PoolError},
reflect::{FieldMut, FieldRef, Reflect, ReflectArray, ReflectList},
type_traits::ComponentProvider,
uuid::Uuid,
visitor::{Visit, VisitResult, Visitor},
TypeUuidProvider,
},
engine::{task::TaskPoolHandler, GraphicsContext, ScriptMessageDispatcher},
engine::{input::InputState, task::TaskPoolHandler, GraphicsContext, ScriptMessageDispatcher},
event::Event,
gui::UiContainer,
plugin::{Plugin, PluginContainer},
scene::{base::NodeScriptMessage, node::Node, Scene},
scene::{base::NodeScriptMessage, graph::GraphError, node::Node, Scene},
};
use fyrox_core::pool::PoolError;
use fyrox_core::reflect::FieldMut;
pub use fyrox_core_derive::ScriptMessagePayload;
use fyrox_graph::BaseSceneGraph;
use std::{
any::{Any, TypeId},
fmt::{Debug, Formatter},
fmt::{Debug, Display, Formatter},
ops::{Deref, DerefMut},
str::FromStr,
sync::mpsc::Sender,
};
pub mod constructor;
pub(crate) trait UniversalScriptContext {
@@ -336,7 +334,7 @@ pub struct ScriptContext<'a, 'b, 'c> {
/// # use fyrox_impl::{
/// # core::{reflect::prelude::*, type_traits::prelude::*, visitor::prelude::*},
/// # plugin::Plugin,
/// # script::{ScriptContext, ScriptTrait},
/// # script::{ScriptContext, ScriptTrait, ScriptResult},
/// # };
/// #
/// #[derive(Visit, Reflect, Default, Debug)]
@@ -352,10 +350,12 @@ pub struct ScriptContext<'a, 'b, 'c> {
/// struct MyScript {}
///
/// impl ScriptTrait for MyScript {
/// fn on_update(&mut self, ctx: &mut ScriptContext) {
/// fn on_update(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
/// let game = ctx.plugins.get::<Game>();
///
/// println!("Player name is: {}", game.player_name);
///
/// Ok(())
/// }
/// }
/// ```
@@ -598,6 +598,58 @@ impl UniversalScriptContext for ScriptDeinitContext<'_, '_, '_> {
}
}
pub type AnyScriptError = Box<dyn std::error::Error>;
pub enum ScriptError {
GraphError(GraphError),
PoolError(PoolError),
AnyError(AnyScriptError),
}
impl From<GraphError> for ScriptError {
fn from(value: GraphError) -> Self {
Self::GraphError(value)
}
}
impl From<PoolError> for ScriptError {
fn from(value: PoolError) -> Self {
Self::PoolError(value)
}
}
impl From<AnyScriptError> for ScriptError {
fn from(value: AnyScriptError) -> Self {
Self::AnyError(value)
}
}
impl std::error::Error for ScriptError {}
impl Display for ScriptError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ScriptError::GraphError(err) => {
write!(f, "{}", err)
}
ScriptError::PoolError(err) => {
write!(f, "{}", err)
}
ScriptError::AnyError(err) => {
write!(f, "{}", err)
}
}
}
}
impl Debug for ScriptError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self)
}
}
pub type ScriptResult = Result<(), ScriptError>;
/// Script is a set predefined methods that are called on various stages by the engine. It is used to add
/// custom behaviour to game entities.
pub trait ScriptTrait: BaseScript + ComponentProvider {
@@ -610,16 +662,25 @@ pub trait ScriptTrait: BaseScript + ComponentProvider {
/// loaded the instance. Internal flag will tell the engine that the script is initialized and this
/// method **will not** be called. This is intentional design decision to be able to create save files
/// in games. If you need a method that will be called in any case, use [`ScriptTrait::on_start`].
fn on_init(&mut self, #[allow(unused_variables)] ctx: &mut ScriptContext) {}
fn on_init(&mut self, #[allow(unused_variables)] ctx: &mut ScriptContext) -> ScriptResult {
Ok(())
}
/// The method is called after [`ScriptTrait::on_init`], but in separate pass, which means that all
/// script instances are already initialized. However, if implementor of this method creates a new
/// node with a script, there will be a second pass of initialization. The method is guaranteed to
/// be called once.
fn on_start(&mut self, #[allow(unused_variables)] ctx: &mut ScriptContext) {}
fn on_start(&mut self, #[allow(unused_variables)] ctx: &mut ScriptContext) -> ScriptResult {
Ok(())
}
/// The method is called when the script is about to be destroyed. It is guaranteed to be called last.
fn on_deinit(&mut self, #[allow(unused_variables)] ctx: &mut ScriptDeinitContext) {}
fn on_deinit(
&mut self,
#[allow(unused_variables)] ctx: &mut ScriptDeinitContext,
) -> ScriptResult {
Ok(())
}
/// Called when there is an event from the OS. The method allows you to "listen" for events
/// coming from the main window of your game. It could be used to react to pressed keys, mouse movements,
@@ -628,13 +689,16 @@ pub trait ScriptTrait: BaseScript + ComponentProvider {
&mut self,
#[allow(unused_variables)] event: &Event<()>,
#[allow(unused_variables)] ctx: &mut ScriptContext,
) {
) -> ScriptResult {
Ok(())
}
/// Performs a single update tick of the script. The method may be called multiple times per frame, but it is guaranteed
/// that the rate of call is stable and by default it will be called 60 times per second, but can be changed by using
/// [`crate::engine::executor::Executor::set_desired_update_rate`] method.
fn on_update(&mut self, #[allow(unused_variables)] ctx: &mut ScriptContext) {}
fn on_update(&mut self, #[allow(unused_variables)] ctx: &mut ScriptContext) -> ScriptResult {
Ok(())
}
/// Allows you to react to certain script messages. It could be used for communication between scripts; to
/// bypass borrowing issues. If you need to receive messages of a particular type, you must subscribe to a type
@@ -645,7 +709,7 @@ pub trait ScriptTrait: BaseScript + ComponentProvider {
/// core::{reflect::prelude::*, uuid::Uuid, visitor::prelude::*, type_traits::prelude::*},
/// core::TypeUuidProvider,
/// script::ScriptTrait,
/// script::{ScriptContext, ScriptMessageContext, ScriptMessagePayload},
/// script::{ScriptContext, ScriptMessageContext, ScriptResult, ScriptMessagePayload},
/// };
///
/// struct Message;
@@ -660,19 +724,21 @@ pub trait ScriptTrait: BaseScript + ComponentProvider {
/// # }
///
/// impl ScriptTrait for MyScript {
/// fn on_start(&mut self, ctx: &mut ScriptContext) {
/// fn on_start(&mut self, ctx: &mut ScriptContext) -> ScriptResult {
/// // Subscription is mandatory to receive any message of the type!
/// ctx.message_dispatcher.subscribe_to::<Message>(ctx.handle)
/// ctx.message_dispatcher.subscribe_to::<Message>(ctx.handle);
/// Ok(())
/// }
///
/// fn on_message(
/// &mut self,
/// message: &mut dyn ScriptMessagePayload,
/// ctx: &mut ScriptMessageContext,
/// ) {
/// ) -> ScriptResult {
/// if let Some(message) = message.downcast_ref::<Message>() {
/// // Do something.
/// }
/// Ok(())
/// }
/// }
/// ```
@@ -680,7 +746,8 @@ pub trait ScriptTrait: BaseScript + ComponentProvider {
&mut self,
#[allow(unused_variables)] message: &mut dyn ScriptMessagePayload,
#[allow(unused_variables)] ctx: &mut ScriptMessageContext,
) {
) -> ScriptResult {
Ok(())
}
}
+9 -3
View File
@@ -21,6 +21,8 @@
//! Flying camera controller script is used to create flying cameras, that can be rotated via mouse and moved via keyboard keys.
//! See [`FlyingCameraController`] docs for more info and usage examples.
use fyrox::graph::BaseSceneGraph;
use fyrox::script::ScriptResult;
use fyrox::{
core::{
algebra::{UnitQuaternion, UnitVector3, Vector3},
@@ -203,7 +205,7 @@ impl_component_provider!(FlyingCameraController);
uuid_provider!(FlyingCameraController = "8d9e2feb-8c61-482c-8ba4-b0b13b201113");
impl ScriptTrait for FlyingCameraController {
fn on_os_event(&mut self, event: &Event<()>, context: &mut ScriptContext) {
fn on_os_event(&mut self, event: &Event<()>, context: &mut ScriptContext) -> ScriptResult {
match event {
Event::WindowEvent {
event: WindowEvent::KeyboardInput { event, .. },
@@ -234,12 +236,14 @@ impl ScriptTrait for FlyingCameraController {
}
_ => {}
}
Ok(())
}
fn on_update(&mut self, context: &mut ScriptContext) {
fn on_update(&mut self, context: &mut ScriptContext) -> ScriptResult {
let mut new_velocity = Vector3::default();
let this = &mut context.scene.graph[context.handle];
let this = context.scene.graph.try_get_node_mut(context.handle)?;
if self.move_forward {
new_velocity += this.look_vector();
@@ -290,5 +294,7 @@ impl ScriptTrait for FlyingCameraController {
) * yaw,
)
.offset(*self.velocity);
Ok(())
}
}