use std::str::FromStr; use bevy::prelude::*; use bevy_mod_scripting::core::{ bindings::function::{ from::Val, namespace::{GlobalNamespace, NamespaceBuilder}, script_function::FunctionCallContext, }, callback_labels, error::InteropError, event::ScriptCallbackEvent, }; use uuid::Uuid; use crate::{components::DirworldEntity, conditionals::Condition}; callback_labels!(OnUpdate => "on_update"); pub fn trigger_update(mut w: EventWriter) { w.send(ScriptCallbackEvent::new_for_all(OnUpdate, vec![])); } // ACTUAL API STUFF BELOW THIS POINT {{{ macro_rules! register_fns { ($world:expr, $($function:expr),+) => { { NamespaceBuilder::::new_unregistered($world) $(.register(stringify!($function), $function))+; } }; } pub fn register(world: &mut World) { register_fns!( world, translate, rotate, get_dirworld_id, condition_true, condition_ancestor_of, condition_descendant_of, condition_parent_of, condition_child_of, condition_in_room, condition_object_in_room ) } fn translate(ctx: FunctionCallContext, entity: Val, translation: Val) { let world = ctx.world().unwrap(); world.with_global_access(|world| { if let Some(mut transform) = world.entity_mut(*entity).get_mut::() { transform.translation += *translation; } }); } fn rotate(ctx: FunctionCallContext, entity: Val, axis: Val, angle: f32) { let world = ctx.world().unwrap(); world.with_global_access(|world| { if let Some(mut transform) = world.entity_mut(*entity).get_mut::() { transform.rotation *= Quat::from_axis_angle(*axis, angle); } }); } fn get_dirworld_id(ctx: FunctionCallContext, entity: Val) -> Result { let world = ctx.world()?; let mut result = Ok(Default::default()); world.with_global_access(|world| { result = if let Some(dirworld_entity) = world.entity(*entity).get::() { Ok(dirworld_entity .payload .as_ref() .map(|p| p.id.to_string()) .unwrap()) } else { Err(InteropError::missing_entity(*entity)) }; }); result } // Conditionals fn condition_true(ctx: FunctionCallContext) -> Result { let world = ctx.world()?; let mut result = Ok(Default::default()); world.with_global_access(|world| { result = Ok(Condition::True.evaluate(world)); }); result } fn condition_ancestor_of( ctx: FunctionCallContext, ancestor: String, descendant: String, ) -> Result { let Ok(ancestor) = Uuid::from_str(&ancestor) else { warn!("Provided ancestor is not a valid UUID"); return Ok(false); }; let Ok(descendant) = Uuid::from_str(&descendant) else { warn!("Provided descendant is not a valid UUID"); return Ok(false); }; let world = ctx.world()?; let mut result = Ok(Default::default()); world.with_global_access(|world| { result = Ok(Condition::AncestorOf { ancestor, descendant, } .evaluate(world)); }); result } fn condition_descendant_of( ctx: FunctionCallContext, descendant: String, ancestor: String, ) -> Result { let Ok(ancestor) = Uuid::from_str(&ancestor) else { warn!("Provided ancestor is not a valid UUID"); return Ok(false); }; let Ok(descendant) = Uuid::from_str(&descendant) else { warn!("Provided descendant is not a valid UUID"); return Ok(false); }; let world = ctx.world()?; let mut result = Ok(Default::default()); world.with_global_access(|world| { result = Ok(Condition::DescendantOf { ancestor, descendant, } .evaluate(world)); }); result } fn condition_parent_of( ctx: FunctionCallContext, parent: String, child: String, ) -> Result { let Ok(parent) = Uuid::from_str(&parent) else { warn!("Provided ancestor is not a valid UUID"); return Ok(false); }; let Ok(child) = Uuid::from_str(&child) else { warn!("Provided descendant is not a valid UUID"); return Ok(false); }; let world = ctx.world()?; let mut result = Ok(Default::default()); world.with_global_access(|world| { result = Ok(Condition::ParentOf { parent, child }.evaluate(world)); }); result } fn condition_child_of( ctx: FunctionCallContext, child: String, parent: String, ) -> Result { let Ok(parent) = Uuid::from_str(&parent) else { warn!("Provided ancestor is not a valid UUID"); return Ok(false); }; let Ok(child) = Uuid::from_str(&child) else { warn!("Provided descendant is not a valid UUID"); return Ok(false); }; let world = ctx.world()?; let mut result = Ok(Default::default()); world.with_global_access(|world| { result = Ok(Condition::ChildOf { parent, child }.evaluate(world)); }); result } fn condition_in_room( ctx: FunctionCallContext, room: String, ) -> Result { let Ok(room) = Uuid::from_str(&room) else { warn!("Provided room is not a valid UUID"); return Ok(false); }; let world = ctx.world()?; let mut result = Ok(Default::default()); world.with_global_access(|world| { result = Ok(Condition::InRoom(room).evaluate(world)); }); result } fn condition_object_in_room( ctx: FunctionCallContext, object: String ) -> Result { let Ok(object) = Uuid::from_str(&object) else { warn!("Provided object is not a valid UUID"); return Ok(false); }; let world = ctx.world()?; let mut result = Ok(Default::default()); world.with_global_access(|world| { result = Ok(Condition::ObjectInRoom(object).evaluate(world)); }); result } // }}}