Create an early scripting engine #2
|
@ -120,7 +120,6 @@ impl Iterator for DynamicViewIter {
|
|||
continue;
|
||||
}
|
||||
|
||||
//let world = unsafe { self.world_ptr.as_ref() };
|
||||
let world = self.world_ptr.as_ref();
|
||||
|
||||
self.fetchers = self.queries.iter()
|
||||
|
@ -153,8 +152,6 @@ pub struct ReflectedIterator {
|
|||
}
|
||||
|
||||
impl ReflectedIterator {
|
||||
|
||||
|
||||
#[cfg(feature = "lua")]
|
||||
pub fn next_lua<'a>(&mut self, lua: &'a mlua::Lua) -> Option<ReflectedRow<'a>> {
|
||||
|
||||
|
@ -167,11 +164,6 @@ impl ReflectedIterator {
|
|||
.map(|r| NonNull::from(r.deref()));
|
||||
}
|
||||
|
||||
/* let mut row = ReflectedRow {
|
||||
entity: row.entity,
|
||||
row: row.item,
|
||||
}; */
|
||||
|
||||
let mut dynamic_row = vec![];
|
||||
for d in row.item.iter() {
|
||||
let id = d.info.type_id.as_rust();
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
pub mod dynamic_iter;
|
||||
use anyhow::anyhow;
|
||||
pub use dynamic_iter::*;
|
||||
|
||||
pub mod world;
|
||||
use lyra_game::{game::GameStages, plugin::Plugin};
|
||||
use lyra_resource::ResourceManager;
|
||||
use tracing::{debug, debug_span, error, trace};
|
||||
pub use world::*;
|
||||
|
||||
pub mod script;
|
||||
|
@ -20,13 +16,15 @@ pub mod wrappers;
|
|||
pub mod proxy;
|
||||
pub use proxy::*;
|
||||
|
||||
pub mod system;
|
||||
pub use system::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
use std::{any::TypeId, ptr::NonNull, sync::Mutex};
|
||||
use std::{any::TypeId, sync::Mutex};
|
||||
|
||||
use lyra_ecs::{
|
||||
query::{Entities, ResMut, View},
|
||||
DynamicBundle, World,
|
||||
};
|
||||
use lyra_reflect::{FromType, Reflect, TypeRegistry};
|
||||
|
@ -38,13 +36,9 @@ pub type LuaContext = Mutex<mlua::Lua>;
|
|||
pub const FN_NAME_INTERNAL_REFLECT_TYPE: &str = "__lyra_internal_reflect_type";
|
||||
pub const FN_NAME_INTERNAL_REFLECT: &str = "__lyra_internal_reflect";
|
||||
|
||||
use crate::{
|
||||
GameScriptExt, ScriptApiProviders, ScriptBorrow, ScriptContexts, ScriptData,
|
||||
ScriptDynamicBundle, ScriptError, ScriptHost, ScriptList, ScriptWorldPtr,
|
||||
};
|
||||
|
||||
use self::providers::{LyraEcsApiProvider, LyraMathApiProvider, UtilityApiProvider};
|
||||
use crate::{ScriptBorrow, ScriptDynamicBundle};
|
||||
|
||||
/// A trait used for registering a Lua type with the world.
|
||||
pub trait RegisterLuaType {
|
||||
/// Register a type to lua that **is not wrapped**.
|
||||
fn register_lua_type<'a, T>(&mut self)
|
||||
|
@ -113,232 +107,4 @@ impl mlua::UserData for ScriptDynamicBundle {
|
|||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// A system that creates the script contexts in the world as new scripts are found
|
||||
pub fn lua_scripts_create_contexts(
|
||||
mut host: ResMut<LuaHost>,
|
||||
mut contexts: ResMut<ScriptContexts<LuaContext>>,
|
||||
mut providers: ResMut<ScriptApiProviders<LuaHost>>,
|
||||
view: View<(Entities, &ScriptList<LuaScript>)>,
|
||||
) -> anyhow::Result<()> {
|
||||
for (en, scripts) in view.into_iter() {
|
||||
for script in scripts.iter() {
|
||||
if !contexts.has_context(script.id()) {
|
||||
let script_data = ScriptData {
|
||||
name: script.name().to_string(),
|
||||
script_id: script.id(),
|
||||
entity: en,
|
||||
};
|
||||
|
||||
let script_name = script.name();
|
||||
let _span = debug_span!("lua", script = script_name).entered();
|
||||
|
||||
if let Some(script_res) = &script.res_handle().try_data_ref() {
|
||||
debug!("Loading script...");
|
||||
let mut script_ctx =
|
||||
host.load_script(&script_res.bytes, &script_data, &mut providers)?;
|
||||
trace!("Finished loading script");
|
||||
|
||||
debug!("Setting up script...");
|
||||
host.setup_script(&script_data, &mut script_ctx, &mut providers)?;
|
||||
trace!("Finished setting up script");
|
||||
|
||||
contexts.add_context(script.id(), script_ctx);
|
||||
} else {
|
||||
trace!("Script is not loaded yet, skipping for now");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// A system that triggers a reload of watched script resources.
|
||||
///
|
||||
/// Note: This only works if the script is watched. See [`lyra_resource::ResourceManager::watch`].
|
||||
pub fn lua_scripts_reload_system(
|
||||
mut contexts: ResMut<ScriptContexts<LuaContext>>,
|
||||
mut resman: ResMut<ResourceManager>,
|
||||
view: View<&ScriptList<LuaScript>>,
|
||||
) -> anyhow::Result<()> {
|
||||
for scripts in view.into_iter() {
|
||||
for script in scripts.iter() {
|
||||
let handle = script.res_handle();
|
||||
if handle.is_watched() {
|
||||
let handle_path = handle.path();
|
||||
let watch_recv = resman.watcher_event_recv(&handle_path).unwrap();
|
||||
|
||||
match watch_recv.try_recv() {
|
||||
Ok(ev) => {
|
||||
let evs =
|
||||
ev.map_err(|e| anyhow!("Script watcher ran into errors: {:?}", e))?;
|
||||
|
||||
if evs.iter().any(|ev| ev.event.kind.is_modify()) {
|
||||
debug!(
|
||||
"Detected change of '{}' script, triggering reload",
|
||||
handle_path
|
||||
);
|
||||
|
||||
contexts.remove_context(script.id()).unwrap();
|
||||
resman.reload(handle)?;
|
||||
}
|
||||
}
|
||||
Err(e) => match e {
|
||||
lyra_resource::channel::TryRecvError::Empty => {}
|
||||
lyra_resource::channel::TryRecvError::Disconnected => {
|
||||
resman.stop_watching(&handle_path).unwrap();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn lua_call_script_function(world: &mut World, stage_name: &str) -> anyhow::Result<()> {
|
||||
let world_ptr = ScriptWorldPtr::from_ref(&world);
|
||||
let mut host = world.get_resource_mut::<LuaHost>();
|
||||
let mut contexts = world.get_resource_mut::<ScriptContexts<LuaContext>>();
|
||||
let mut providers = world.get_resource_mut::<ScriptApiProviders<LuaHost>>();
|
||||
|
||||
for (en, scripts) in world.view_iter::<(Entities, &ScriptList<LuaScript>)>() {
|
||||
for script in scripts.iter() {
|
||||
let script_data = ScriptData {
|
||||
name: script.name().to_string(),
|
||||
script_id: script.id(),
|
||||
entity: en,
|
||||
};
|
||||
|
||||
if let Some(ctx) = contexts.get_context_mut(script.id()) {
|
||||
trace!(
|
||||
"Running '{}' function in script '{}'",
|
||||
stage_name,
|
||||
script.name()
|
||||
);
|
||||
|
||||
match host.call_script(
|
||||
world_ptr.clone(),
|
||||
&script_data,
|
||||
ctx,
|
||||
&mut providers,
|
||||
stage_name,
|
||||
) {
|
||||
Ok(()) => {}
|
||||
Err(e) => match e {
|
||||
ScriptError::MluaError(m) => {
|
||||
error!("Script '{}' ran into an error: {}", script.name(), m);
|
||||
}
|
||||
ScriptError::Other(_) => return Err(e.into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This system executes the 'on_update' function of lua scripts in the world. It is meant to run
|
||||
/// during the 'GameStages::Update' stage.
|
||||
pub fn lua_script_update_stage_system(world: &mut World) -> anyhow::Result<()> {
|
||||
lua_call_script_function(world, "on_update")
|
||||
}
|
||||
|
||||
/// This system executes the 'on_pre_update' function of lua scripts in the world. It is meant to run
|
||||
/// during the 'GameStages::PreUpdate' stage.
|
||||
pub fn lua_script_pre_update_stage_system(world: &mut World) -> anyhow::Result<()> {
|
||||
lua_call_script_function(world, "on_pre_update")
|
||||
}
|
||||
|
||||
/// This system executes the 'on_post_update' function of lua scripts in the world. It is meant to run
|
||||
/// during the 'GameStages::PostUpdate' stage.
|
||||
pub fn lua_script_post_update_stage_system(world: &mut World) -> anyhow::Result<()> {
|
||||
lua_call_script_function(world, "on_post_update")
|
||||
}
|
||||
|
||||
/// This system executes the 'on_first' function of lua scripts in the world. It is meant to run
|
||||
/// during the 'GameStages::First' stage.
|
||||
pub fn lua_script_first_stage_system(world: &mut World) -> anyhow::Result<()> {
|
||||
lua_call_script_function(world, "on_first")
|
||||
}
|
||||
|
||||
/// This system executes the 'on_last' function of lua scripts in the world. It is meant to run
|
||||
/// during the 'GameStages::Last' stage.
|
||||
pub fn lua_script_last_stage_system(world: &mut World) -> anyhow::Result<()> {
|
||||
lua_call_script_function(world, "on_last")
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LuaScriptingPlugin;
|
||||
|
||||
impl Plugin for LuaScriptingPlugin {
|
||||
fn setup(&self, game: &mut lyra_game::game::Game) {
|
||||
let world = game.world();
|
||||
|
||||
world.add_resource_default::<TypeRegistry>();
|
||||
|
||||
world.add_resource_default::<LuaHost>();
|
||||
world.add_resource_default::<ScriptApiProviders<LuaHost>>();
|
||||
world.add_resource_default::<ScriptContexts<LuaContext>>();
|
||||
|
||||
let mut loader = world
|
||||
.try_get_resource_mut::<ResourceManager>()
|
||||
.expect("Add 'ResourceManager' to the world before trying to add this plugin");
|
||||
loader.register_loader::<LuaLoader>();
|
||||
drop(loader);
|
||||
|
||||
game.add_script_api_provider::<LuaHost, _>(UtilityApiProvider);
|
||||
game.add_script_api_provider::<LuaHost, _>(LyraEcsApiProvider);
|
||||
game.add_script_api_provider::<LuaHost, _>(LyraMathApiProvider);
|
||||
|
||||
game.add_system_to_stage(
|
||||
GameStages::First,
|
||||
"lua_create_contexts",
|
||||
lua_scripts_create_contexts,
|
||||
&[],
|
||||
)
|
||||
.add_system_to_stage(
|
||||
GameStages::First,
|
||||
"lua_reload_scripts",
|
||||
lua_scripts_reload_system,
|
||||
&["lua_create_contexts"],
|
||||
)
|
||||
.add_system_to_stage(
|
||||
GameStages::First,
|
||||
"lua_first_stage",
|
||||
lua_script_first_stage_system,
|
||||
&["lua_reload_scripts"],
|
||||
)
|
||||
// cannot depend on 'lua_create_contexts' since it will cause a panic.
|
||||
// the staged executor separates the executor of a single stage so this system
|
||||
// cannot depend on the other one.
|
||||
.add_system_to_stage(
|
||||
GameStages::PreUpdate,
|
||||
"lua_pre_update",
|
||||
lua_script_pre_update_stage_system,
|
||||
&[],
|
||||
)
|
||||
.add_system_to_stage(
|
||||
GameStages::Update,
|
||||
"lua_update",
|
||||
lua_script_update_stage_system,
|
||||
&[],
|
||||
)
|
||||
.add_system_to_stage(
|
||||
GameStages::PostUpdate,
|
||||
"lua_post_update",
|
||||
lua_script_post_update_stage_system,
|
||||
&[],
|
||||
)
|
||||
.add_system_to_stage(
|
||||
GameStages::Last,
|
||||
"lua_last_stage",
|
||||
lua_script_last_stage_system,
|
||||
&[],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
use anyhow::anyhow;
|
||||
use lyra_ecs::{query::{Entities, ResMut, View}, World};
|
||||
use lyra_game::{game::GameStages, plugin::Plugin};
|
||||
use lyra_reflect::TypeRegistry;
|
||||
use lyra_resource::ResourceManager;
|
||||
use tracing::{debug, debug_span, error, trace};
|
||||
|
||||
use crate::{GameScriptExt, ScriptApiProviders, ScriptContexts, ScriptData, ScriptError, ScriptHost, ScriptList, ScriptWorldPtr};
|
||||
|
||||
use super::{providers::{LyraEcsApiProvider, LyraMathApiProvider, UtilityApiProvider}, LuaContext, LuaHost, LuaLoader, LuaScript};
|
||||
|
||||
/// A system that creates the script contexts in the world as new scripts are found
|
||||
pub fn lua_scripts_create_contexts(
|
||||
mut host: ResMut<LuaHost>,
|
||||
mut contexts: ResMut<ScriptContexts<LuaContext>>,
|
||||
mut providers: ResMut<ScriptApiProviders<LuaHost>>,
|
||||
view: View<(Entities, &ScriptList<LuaScript>)>,
|
||||
) -> anyhow::Result<()> {
|
||||
for (en, scripts) in view.into_iter() {
|
||||
for script in scripts.iter() {
|
||||
if !contexts.has_context(script.id()) {
|
||||
let script_data = ScriptData {
|
||||
name: script.name().to_string(),
|
||||
script_id: script.id(),
|
||||
entity: en,
|
||||
};
|
||||
|
||||
let script_name = script.name();
|
||||
let _span = debug_span!("lua", script = script_name).entered();
|
||||
|
||||
if let Some(script_res) = &script.res_handle().try_data_ref() {
|
||||
debug!("Loading script...");
|
||||
let mut script_ctx =
|
||||
host.load_script(&script_res.bytes, &script_data, &mut providers)?;
|
||||
trace!("Finished loading script");
|
||||
|
||||
debug!("Setting up script...");
|
||||
host.setup_script(&script_data, &mut script_ctx, &mut providers)?;
|
||||
trace!("Finished setting up script");
|
||||
|
||||
contexts.add_context(script.id(), script_ctx);
|
||||
} else {
|
||||
trace!("Script is not loaded yet, skipping for now");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// A system that triggers a reload of watched script resources.
|
||||
///
|
||||
/// Note: This only works if the script is watched. See [`lyra_resource::ResourceManager::watch`].
|
||||
pub fn lua_scripts_reload_system(
|
||||
mut contexts: ResMut<ScriptContexts<LuaContext>>,
|
||||
mut resman: ResMut<ResourceManager>,
|
||||
view: View<&ScriptList<LuaScript>>,
|
||||
) -> anyhow::Result<()> {
|
||||
for scripts in view.into_iter() {
|
||||
for script in scripts.iter() {
|
||||
let handle = script.res_handle();
|
||||
if handle.is_watched() {
|
||||
let handle_path = handle.path();
|
||||
let watch_recv = resman.watcher_event_recv(&handle_path).unwrap();
|
||||
|
||||
match watch_recv.try_recv() {
|
||||
Ok(ev) => {
|
||||
let evs =
|
||||
ev.map_err(|e| anyhow!("Script watcher ran into errors: {:?}", e))?;
|
||||
|
||||
if evs.iter().any(|ev| ev.event.kind.is_modify()) {
|
||||
debug!(
|
||||
"Detected change of '{}' script, triggering reload",
|
||||
handle_path
|
||||
);
|
||||
|
||||
contexts.remove_context(script.id()).unwrap();
|
||||
resman.reload(handle)?;
|
||||
}
|
||||
}
|
||||
Err(e) => match e {
|
||||
lyra_resource::channel::TryRecvError::Empty => {}
|
||||
lyra_resource::channel::TryRecvError::Disconnected => {
|
||||
resman.stop_watching(&handle_path).unwrap();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn lua_call_script_function(world: &mut World, stage_name: &str) -> anyhow::Result<()> {
|
||||
let world_ptr = ScriptWorldPtr::from_ref(&world);
|
||||
let mut host = world.get_resource_mut::<LuaHost>();
|
||||
let mut contexts = world.get_resource_mut::<ScriptContexts<LuaContext>>();
|
||||
let mut providers = world.get_resource_mut::<ScriptApiProviders<LuaHost>>();
|
||||
|
||||
for (en, scripts) in world.view_iter::<(Entities, &ScriptList<LuaScript>)>() {
|
||||
for script in scripts.iter() {
|
||||
let script_data = ScriptData {
|
||||
name: script.name().to_string(),
|
||||
script_id: script.id(),
|
||||
entity: en,
|
||||
};
|
||||
|
||||
if let Some(ctx) = contexts.get_context_mut(script.id()) {
|
||||
trace!(
|
||||
"Running '{}' function in script '{}'",
|
||||
stage_name,
|
||||
script.name()
|
||||
);
|
||||
|
||||
match host.call_script(
|
||||
world_ptr.clone(),
|
||||
&script_data,
|
||||
ctx,
|
||||
&mut providers,
|
||||
stage_name,
|
||||
) {
|
||||
Ok(()) => {}
|
||||
Err(e) => match e {
|
||||
ScriptError::MluaError(m) => {
|
||||
error!("Script '{}' ran into an error: {}", script.name(), m);
|
||||
}
|
||||
ScriptError::Other(_) => return Err(e.into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This system executes the 'on_update' function of lua scripts in the world. It is meant to run
|
||||
/// during the 'GameStages::Update' stage.
|
||||
pub fn lua_script_update_stage_system(world: &mut World) -> anyhow::Result<()> {
|
||||
lua_call_script_function(world, "on_update")
|
||||
}
|
||||
|
||||
/// This system executes the 'on_pre_update' function of lua scripts in the world. It is meant to run
|
||||
/// during the 'GameStages::PreUpdate' stage.
|
||||
pub fn lua_script_pre_update_stage_system(world: &mut World) -> anyhow::Result<()> {
|
||||
lua_call_script_function(world, "on_pre_update")
|
||||
}
|
||||
|
||||
/// This system executes the 'on_post_update' function of lua scripts in the world. It is meant to run
|
||||
/// during the 'GameStages::PostUpdate' stage.
|
||||
pub fn lua_script_post_update_stage_system(world: &mut World) -> anyhow::Result<()> {
|
||||
lua_call_script_function(world, "on_post_update")
|
||||
}
|
||||
|
||||
/// This system executes the 'on_first' function of lua scripts in the world. It is meant to run
|
||||
/// during the 'GameStages::First' stage.
|
||||
pub fn lua_script_first_stage_system(world: &mut World) -> anyhow::Result<()> {
|
||||
lua_call_script_function(world, "on_first")
|
||||
}
|
||||
|
||||
/// This system executes the 'on_last' function of lua scripts in the world. It is meant to run
|
||||
/// during the 'GameStages::Last' stage.
|
||||
pub fn lua_script_last_stage_system(world: &mut World) -> anyhow::Result<()> {
|
||||
lua_call_script_function(world, "on_last")
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LuaScriptingPlugin;
|
||||
|
||||
impl Plugin for LuaScriptingPlugin {
|
||||
fn setup(&self, game: &mut lyra_game::game::Game) {
|
||||
let world = game.world();
|
||||
|
||||
world.add_resource_default::<TypeRegistry>();
|
||||
|
||||
world.add_resource_default::<LuaHost>();
|
||||
world.add_resource_default::<ScriptApiProviders<LuaHost>>();
|
||||
world.add_resource_default::<ScriptContexts<LuaContext>>();
|
||||
|
||||
let mut loader = world
|
||||
.try_get_resource_mut::<ResourceManager>()
|
||||
.expect("Add 'ResourceManager' to the world before trying to add this plugin");
|
||||
loader.register_loader::<LuaLoader>();
|
||||
drop(loader);
|
||||
|
||||
game.add_script_api_provider::<LuaHost, _>(UtilityApiProvider);
|
||||
game.add_script_api_provider::<LuaHost, _>(LyraEcsApiProvider);
|
||||
game.add_script_api_provider::<LuaHost, _>(LyraMathApiProvider);
|
||||
|
||||
game.add_system_to_stage(
|
||||
GameStages::First,
|
||||
"lua_create_contexts",
|
||||
lua_scripts_create_contexts,
|
||||
&[],
|
||||
)
|
||||
.add_system_to_stage(
|
||||
GameStages::First,
|
||||
"lua_reload_scripts",
|
||||
lua_scripts_reload_system,
|
||||
&["lua_create_contexts"],
|
||||
)
|
||||
.add_system_to_stage(
|
||||
GameStages::First,
|
||||
"lua_first_stage",
|
||||
lua_script_first_stage_system,
|
||||
&["lua_reload_scripts"],
|
||||
)
|
||||
// cannot depend on 'lua_create_contexts' since it will cause a panic.
|
||||
// the staged executor separates the executor of a single stage so this system
|
||||
// cannot depend on the other one.
|
||||
.add_system_to_stage(
|
||||
GameStages::PreUpdate,
|
||||
"lua_pre_update",
|
||||
lua_script_pre_update_stage_system,
|
||||
&[],
|
||||
)
|
||||
.add_system_to_stage(
|
||||
GameStages::Update,
|
||||
"lua_update",
|
||||
lua_script_update_stage_system,
|
||||
&[],
|
||||
)
|
||||
.add_system_to_stage(
|
||||
GameStages::PostUpdate,
|
||||
"lua_post_update",
|
||||
lua_script_post_update_stage_system,
|
||||
&[],
|
||||
)
|
||||
.add_system_to_stage(
|
||||
GameStages::Last,
|
||||
"lua_last_stage",
|
||||
lua_script_last_stage_system,
|
||||
&[],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -164,24 +164,6 @@ impl mlua::UserData for ScriptWorldPtr {
|
|||
let reflect = ty
|
||||
.call_function::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT_TYPE, ())
|
||||
.expect("Type does not implement 'reflect_type' properly");
|
||||
|
||||
//if let Some(data) = reflect.data {
|
||||
/* let res = reflect.reflect_branch.as_resource_unchecked();
|
||||
if let Some(res_ptr) = res.reflect_arc(this.as_mut()) {
|
||||
let reg_type = this.as_ref().get_type::<RegisteredType>(reflect.reflect_branch.reflect_type_id())
|
||||
.unwrap();
|
||||
let proxy = reg_type.get_data::<ReflectLuaProxy>()
|
||||
.expect("Type does not have ReflectLuaProxy as a TypeData");
|
||||
|
||||
//let res = Arc::new(RwLock::new(data.as_any_box()))
|
||||
(proxy.fn_as_uservalue_ref)(lua, res_ptr)
|
||||
.and_then(|ud| ud.into_lua(lua))
|
||||
|
||||
//Ok(mlua::Value::Nil)
|
||||
} else {
|
||||
Ok(mlua::Value::Nil)
|
||||
} */
|
||||
|
||||
|
||||
let res = reflect.reflect_branch.as_resource_unchecked();
|
||||
if let Some(res_ptr) = res.reflect_ptr(this.as_mut()) {
|
||||
|
|
Loading…
Reference in New Issue