 2c82a2fa0e
			
		
	
	
		2c82a2fa0e
		
			
		
	
	
	
	
		
			
			* Added initial support for bevy 0.16.0 * Removed unnecessary bevy feature * update version references --------- Co-authored-by: Jaroslaw Konik <konikjar@gmail.com>
		
			
				
	
	
		
			174 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use bevy::{prelude::*, log::tracing};
 | |
| use std::{
 | |
|     fmt::Display,
 | |
|     sync::{Arc, Mutex},
 | |
| };
 | |
| 
 | |
| use crate::{
 | |
|     callback::FunctionCallEvent,
 | |
|     promise::{Promise, PromiseInner},
 | |
|     Callback, Callbacks, Runtime, ScriptingError,
 | |
| };
 | |
| 
 | |
| use super::components::Script;
 | |
| 
 | |
| /// Reloads scripts when they are modified.
 | |
| pub(crate) fn reload_scripts<R: Runtime>(
 | |
|     mut commands: Commands,
 | |
|     mut ev_asset: EventReader<AssetEvent<R::ScriptAsset>>,
 | |
|     mut scripts: Query<(Entity, &mut Script<R::ScriptAsset>)>,
 | |
| ) {
 | |
|     for ev in ev_asset.read() {
 | |
|         if let AssetEvent::Modified { id } = ev {
 | |
|             for (entity, script) in &mut scripts {
 | |
|                 if script.script.id() == *id {
 | |
|                     commands.entity(entity).remove::<R::ScriptData>();
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// Processes new scripts. Evaluates them and stores the script data in the entity.
 | |
| #[allow(clippy::type_complexity)]
 | |
| pub(crate) fn process_new_scripts<R: Runtime>(
 | |
|     mut commands: Commands,
 | |
|     mut added_scripted_entities: Query<
 | |
|         (Entity, &mut Script<R::ScriptAsset>),
 | |
|         Without<R::ScriptData>,
 | |
|     >,
 | |
|     scripting_runtime: ResMut<R>,
 | |
|     scripts: Res<Assets<R::ScriptAsset>>,
 | |
|     asset_server: Res<AssetServer>,
 | |
| ) -> Result<(), ScriptingError> {
 | |
|     for (entity, script_component) in &mut added_scripted_entities {
 | |
|         tracing::trace!("evaulating a new script");
 | |
|         if let Some(script) = scripts.get(&script_component.script) {
 | |
|             match scripting_runtime.eval(script, entity) {
 | |
|                 Ok(script_data) => {
 | |
|                     commands.entity(entity).insert(script_data);
 | |
|                 }
 | |
|                 Err(e) => {
 | |
|                     let path = asset_server
 | |
|                         .get_path(&script_component.script)
 | |
|                         .unwrap_or_default();
 | |
|                     tracing::error!("error running script {} {:?}", path, e);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     Ok(())
 | |
| }
 | |
| 
 | |
| /// Initializes callbacks. Registers them in the scripting engine.
 | |
| pub(crate) fn init_callbacks<R: Runtime>(world: &mut World) -> Result<(), ScriptingError> {
 | |
|     let mut callbacks_resource = world
 | |
|         .get_resource_mut::<Callbacks<R>>()
 | |
|         .ok_or(ScriptingError::NoSettingsResource)?;
 | |
| 
 | |
|     let mut callbacks = callbacks_resource
 | |
|         .uninitialized_callbacks
 | |
|         .drain(..)
 | |
|         .collect::<Vec<Callback<R>>>();
 | |
| 
 | |
|     for callback in callbacks.iter_mut() {
 | |
|         if let Ok(mut system) = callback.system.lock() {
 | |
|             system.system.initialize(world);
 | |
| 
 | |
|             let mut scripting_runtime = world
 | |
|                 .get_resource_mut::<R>()
 | |
|                 .ok_or(ScriptingError::NoRuntimeResource)?;
 | |
| 
 | |
|             tracing::trace!("init_callbacks: registering callback: '{}'", callback.name);
 | |
| 
 | |
|             let callback = callback.clone();
 | |
| 
 | |
|             let result = scripting_runtime.register_fn(
 | |
|                 callback.name,
 | |
|                 system.arg_types.clone(),
 | |
|                 move |context, params| {
 | |
|                     let promise = Promise {
 | |
|                         inner: Arc::new(Mutex::new(PromiseInner {
 | |
|                             callbacks: vec![],
 | |
|                             context,
 | |
|                         })),
 | |
|                     };
 | |
| 
 | |
|                     let mut calls = callback
 | |
|                         .calls
 | |
|                         .lock()
 | |
|                         .expect("Failed to lock callback calls mutex");
 | |
| 
 | |
|                     calls.push(FunctionCallEvent {
 | |
|                         promise: promise.clone(),
 | |
|                         params,
 | |
|                     });
 | |
|                     Ok(promise)
 | |
|                 },
 | |
|             );
 | |
|             if let Err(e) = result {
 | |
|                 tracing::error!("error registering function: {:?}", e);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     let callbacks_resource = world
 | |
|         .get_resource_mut::<Callbacks<R>>()
 | |
|         .ok_or(ScriptingError::NoSettingsResource)?;
 | |
|     callbacks_resource
 | |
|         .callbacks
 | |
|         .lock()
 | |
|         .expect("Failed to lock callbacks mutex")
 | |
|         .append(&mut callbacks.clone());
 | |
| 
 | |
|     Ok(())
 | |
| }
 | |
| 
 | |
| /// Processes calls. Calls the user-defined callback systems
 | |
| pub(crate) fn process_calls<R: Runtime>(world: &mut World) -> Result<(), ScriptingError> {
 | |
|     let callbacks_resource = world
 | |
|         .get_resource::<Callbacks<R>>()
 | |
|         .ok_or(ScriptingError::NoSettingsResource)?;
 | |
| 
 | |
|     let callbacks = callbacks_resource
 | |
|         .callbacks
 | |
|         .lock()
 | |
|         .expect("Failed to lock callbacks mutex")
 | |
|         .clone();
 | |
| 
 | |
|     for callback in callbacks.into_iter() {
 | |
|         let calls = callback
 | |
|             .calls
 | |
|             .lock()
 | |
|             .expect("Failed to lock callback calls mutex")
 | |
|             .drain(..)
 | |
|             .collect::<Vec<FunctionCallEvent<R::CallContext, R::Value>>>();
 | |
|         for mut call in calls {
 | |
|             tracing::trace!("process_calls: calling '{}'", callback.name);
 | |
|             let mut system = callback
 | |
|                 .system
 | |
|                 .lock()
 | |
|                 .expect("Failed to lock callback system mutex");
 | |
|             let val = system.call(&call, world);
 | |
|             let mut runtime = world
 | |
|                 .get_resource_mut::<R>()
 | |
|                 .ok_or(ScriptingError::NoRuntimeResource)?;
 | |
| 
 | |
|             let result = call.promise.resolve(runtime.as_mut(), val);
 | |
|             match result {
 | |
|                 Ok(_) => {}
 | |
|                 Err(e) => {
 | |
|                     tracing::error!("error resolving call: {} {:?}", callback.name, e);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     Ok(())
 | |
| }
 | |
| 
 | |
| /// Error logging system
 | |
| pub fn log_errors<E: Display>(In(res): In<Result<(), E>>) {
 | |
|     if let Err(error) = res {
 | |
|         tracing::error!("{}", error);
 | |
|     }
 | |
| }
 |