mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-11 22:50:08 +00:00
improved script api to support errors
This commit is contained in:
+119
-63
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(())
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user