Skip to content

Commit

Permalink
feat: implement asset lua bindings.
Browse files Browse the repository at this point in the history
  • Loading branch information
zicklag committed Nov 7, 2023
1 parent 635325e commit d811463
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 30 deletions.
12 changes: 10 additions & 2 deletions demos/features/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,16 @@ fn main() {
PersistedTextData::register_schema();

// Create a bones bevy renderer from our bones game
BonesBevyRenderer::new(create_game())
// Get a bevy app for running our game
let mut renderer = BonesBevyRenderer::new(create_game());
// Set the app namespace which will be used by the renderer to decide where to put
// persistent storage files.
renderer.app_namespace = (
"org".into(),
"fishfolk".into(),
"bones.demo_features".into(),
);
// Get a bevy app for running our game
renderer
.app()
// We can add our own bevy plugins now
.add_plugins((FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin::default()))
Expand Down
2 changes: 2 additions & 0 deletions demos/scripting/assets/game.yaml
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
update: ./update.lua
version: 1
info: ./info.yaml
2 changes: 2 additions & 0 deletions demos/scripting/assets/info.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name: Scripting Demo Game
gravity: -9.8
6 changes: 3 additions & 3 deletions demos/scripting/assets/update.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
local data = world.resources:get(s"DemoData")
data = s"DemoData":create()
info(data.age)
local info_handle = world.assets.root.info
local info_data = world.assets:get(info_handle)
info(info_data.name)
22 changes: 19 additions & 3 deletions demos/scripting/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ use bones_framework::prelude::*;
#[repr(C)]
struct GameMeta {
update: Handle<LuaScript>,
version: u32,
info: Handle<GameInfoMeta>,
}

#[derive(HasSchema, Default, Clone)]
#[repr(C)]
#[type_data(metadata_asset("info"))]
struct GameInfoMeta {
name: String,
gravity: f32,
}

#[derive(HasSchema, Default, Clone)]
Expand Down Expand Up @@ -33,8 +43,8 @@ pub enum DemoState {
fn main() {
let mut game = Game::new();
game.install_plugin(DefaultGamePlugin);
GameMeta::schema();
DemoData::schema();
GameMeta::register_schema();
DemoData::register_schema();

let default_session = game.sessions.create("default");
default_session
Expand All @@ -51,7 +61,13 @@ fn main() {
state: DemoState::Thinking(20.),
});

BonesBevyRenderer::new(game).app().run();
let mut renderer = BonesBevyRenderer::new(game);
renderer.app_namespace = (
"org".into(),
"fishfolk".into(),
"bones.demo_scripting".into(),
);
renderer.app().run();
}

fn update_script(world: &World, lua_engine: Res<LuaEngine>, meta: Root<GameMeta>) {
Expand Down
26 changes: 9 additions & 17 deletions framework_crates/bones_schema/src/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,9 @@ impl<'pointer> SchemaRef<'pointer> {
/// Create a new [`SchemaRef`] from a raw pointer and it's schema.
///
/// # Safety
/// - `ptr` must point to valid value of whatever the pointee type is.
/// - `ptr` must not be null.
/// - If the `A` type parameter is [`Aligned`] then `inner` must be sufficiently aligned for the
/// pointee type.
/// - `inner` must have correct provenance to allow read and writes of the pointee type.
/// - The lifetime `'a` must be constrained such that this [`PtrMut`] will stay valid and
/// nothing else can read or mutate the pointee while this [`PtrMut`] is live.
/// - The pointee of `ptr` must be accurately described by the given `schema`.
/// - `inner` must have correct provenance to allow read of the pointee type.
/// - The pointer must be valid for the full lifetime of this [`SchemaRef`].
#[track_caller]
pub unsafe fn from_ptr_schema(ptr: *const c_void, schema: &'static Schema) -> Self {
Self {
Expand Down Expand Up @@ -562,7 +558,7 @@ pub enum PrimitiveRef<'a> {
I64(&'a i64),
/// An [`i128`]
I128(&'a i128),
/// An [`f23`]
/// An [`f32`]
F32(&'a f32),
/// An [`f64`]
F64(&'a f64),
Expand Down Expand Up @@ -728,13 +724,9 @@ impl<'pointer> SchemaRefMut<'pointer> {
/// Create a new [`SchemaRefMut`] from a raw pointer and it's schema.
///
/// # Safety
/// - `ptr` must point to valid value of whatever the pointee type is.
/// - `ptr` must not be null.
/// - If the `A` type parameter is [`Aligned`] then `inner` must be sufficiently aligned for the
/// pointee type.
/// - `ptr` must have correct provenance to allow read and writes of the pointee type.
/// - The lifetime `'pointer` must be constrained such that this [`PtrMut`] will stay valid and
/// nothing else can read or mutate the pointee while this [`PtrMut`] is live.
/// - The pointee of `ptr` must be accurately described by the given `schema`.
/// - `inner` must have correct provenance to allow reads and writes of the pointee type.
/// - The pointer must be valid for the full lifetime of this [`SchemaRef`].
pub unsafe fn from_ptr_schema(
ptr: *mut c_void,
schema: &'static Schema,
Expand Down Expand Up @@ -1229,7 +1221,7 @@ pub enum PrimitiveRefMut<'a> {
I64(&'a mut i64),
/// An [`i128`]
I128(&'a mut i128),
/// An [`f23`]
/// An [`f32`]
F32(&'a mut f32),
/// An [`f64`]
F64(&'a mut f64),
Expand Down Expand Up @@ -1821,7 +1813,7 @@ impl<'a> std::fmt::Display for FieldIdx<'a> {
}

/// A wrapper type that implements [`IntoIterator<Item = FieldIdx>`] for an inner string to make
/// it easier to use with [`SchemaRef::get_field_path()`] and other field path methods.
/// it easier to use with [`SchemaRefAccess::field_path()`] and other field path methods.
pub struct FieldPath<T>(pub T);
impl<'a> IntoIterator for FieldPath<&'a str> {
type Item = FieldIdx<'a>;
Expand Down
2 changes: 1 addition & 1 deletion framework_crates/bones_scripting/src/lua.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub mod bindings;
/// Install the scripting plugin.
pub fn lua_game_plugin(game: &mut Game) {
// Register asset type.
LuaScript::schema();
LuaScript::register_schema();

// Add `SchemaLuaMetatable` type data for common types.
bindings::register_lua_typedata();
Expand Down
1 change: 1 addition & 0 deletions framework_crates/bones_scripting/src/lua/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::prelude::*;
#[derive(HasSchema)]
#[schema(no_clone, no_default)]
#[type_data(asset_loader("lua", LuaScriptLoader))]
#[repr(C)]
pub struct LuaScript {
pub source: String,
}
Expand Down
154 changes: 150 additions & 4 deletions framework_crates/bones_scripting/src/lua/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub fn no_newindex(ctx: Context) -> StaticCallback {
)
}

pub fn luaref_metatable(ctx: Context) -> StaticTable {
pub fn ecsref_metatable(ctx: Context) -> StaticTable {
let metatable = Table::new(&ctx);
let static_metatable = ctx.state.registry.stash(&ctx, metatable);
let static_metatable_ = static_metatable.clone();
Expand Down Expand Up @@ -243,7 +243,7 @@ pub fn luaref_metatable(ctx: Context) -> StaticTable {
pub fn resources_metatable(ctx: Context) -> StaticTable {
let metatable = Table::new(&ctx);
let luadata = ctx.luadata();
let luaref_metatable = luadata.table(ctx, luaref_metatable);
let ecsref_metatable = luadata.table(ctx, ecsref_metatable);
metatable
.set(
ctx,
Expand All @@ -253,6 +253,16 @@ pub fn resources_metatable(ctx: Context) -> StaticTable {
.fetch(&luadata.callback(ctx, no_newindex)),
)
.unwrap();
metatable
.set(
ctx,
"__tostring",
AnyCallback::from_fn(&ctx, |ctx, _fuel, stack| {
stack.push_front(piccolo::String::from_static(&ctx, "world.resources").into());
Ok(CallbackReturn::Return)
}),
)
.unwrap();

let get_callback = ctx.state.registry.stash(
&ctx,
Expand Down Expand Up @@ -283,7 +293,7 @@ pub fn resources_metatable(ctx: Context) -> StaticTable {
path: default(),
},
);
data.set_metatable(&ctx, Some(ctx.state.registry.fetch(&luaref_metatable)));
data.set_metatable(&ctx, Some(ctx.state.registry.fetch(&ecsref_metatable)));
stack.push_front(data.into());
}
});
Expand Down Expand Up @@ -332,6 +342,34 @@ pub fn resources_metatable(ctx: Context) -> StaticTable {

pub fn components_metatable(ctx: Context) -> StaticTable {
let metatable = Table::new(&ctx);
metatable
.set(
ctx,
"__tostring",
AnyCallback::from_fn(&ctx, |ctx, _fuel, stack| {
stack.push_front(piccolo::String::from_static(&ctx, "world.components").into());
Ok(CallbackReturn::Return)
}),
)
.unwrap();
metatable
.set(
ctx,
"__newindex",
ctx.state
.registry
.fetch(&ctx.luadata().callback(ctx, no_newindex)),
)
.unwrap();

ctx.state.registry.stash(&ctx, metatable)
}

pub fn assets_metatable(ctx: Context) -> StaticTable {
let metatable = Table::new(&ctx);
let luadata = ctx.luadata();
let ecsref_metatable = luadata.table(ctx, ecsref_metatable);
let ecsref_metatable_ = ecsref_metatable.clone();
metatable
.set(
ctx,
Expand All @@ -341,7 +379,108 @@ pub fn components_metatable(ctx: Context) -> StaticTable {
.fetch(&ctx.luadata().callback(ctx, no_newindex)),
)
.unwrap();
metatable
.set(
ctx,
"__tostring",
AnyCallback::from_fn(&ctx, |ctx, _fuel, stack| {
stack.push_front(piccolo::String::from_static(&ctx, "world.assets").into());
Ok(CallbackReturn::Return)
}),
)
.unwrap();

let get_callback = ctx.state.registry.stash(
&ctx,
AnyCallback::from_fn(&ctx, move |ctx, _fuel, stack| {
let world = stack.pop_front();
let Value::UserData(world) = world else {
return Err(
anyhow::format_err!("Type error on `self` of resources metatable.").into(),
);
};
let world = world.downcast_static::<WorldRef>()?;

let ecsref = stack.pop_front();
let Value::UserData(ecsref) = ecsref else {
return Err(
anyhow::format_err!("Type error on `self` of resources metatable.").into(),
);
};
let ecsref = ecsref.downcast_static::<EcsRef>()?;
let b = ecsref.data.borrow();
let Some(b) = b.access() else {
return Err(anyhow::format_err!("Unable to get value").into());
};
let Some(b) = b.field_path(FieldPath(ecsref.path)) else {
return Err(anyhow::format_err!("Unable to get value").into());
};
let handle = b.into_schema_ref().try_cast::<UntypedHandle>()?;

let assetref = world.with(|world| EcsRef {
data: EcsRefData::Asset(AssetRef {
server: (*world.resources.get::<AssetServer>().unwrap()).clone(),
handle: *handle,
}),
path: default(),
});
let assetref = AnyUserData::new_static(&ctx, assetref);
assetref.set_metatable(&ctx, Some(ctx.state.registry.fetch(&ecsref_metatable_)));

stack.push_front(assetref.into());

Ok(CallbackReturn::Return)
}),
);

metatable
.set(
ctx,
"__index",
AnyCallback::from_fn(&ctx, move |ctx, _fuel, stack| {
let this = stack.pop_front();
let key = stack.pop_front();
let Value::UserData(world) = this else {
return Err(anyhow::format_err!(
"Type error on `self` of resources metatable."
)
.into());
};
let world = world.downcast_static::<WorldRef>()?;

if let Value::String(key) = key {
#[allow(clippy::single_match)]
match key.as_bytes() {
b"root" => {
world.with(|world| {
let asset_server = world.resources.get::<AssetServer>().unwrap();
let root = asset_server.core().root;
let assetref = EcsRef {
data: EcsRefData::Asset(AssetRef {
server: (*asset_server).clone(),
handle: root,
}),
path: default(),
};
let assetref = AnyUserData::new_static(&ctx, assetref);
assetref.set_metatable(
&ctx,
Some(ctx.state.registry.fetch(&ecsref_metatable)),
);
stack.push_front(assetref.into());
});
}
b"get" => {
stack.push_front(ctx.state.registry.fetch(&get_callback).into());
}
_ => (),
}
}

Ok(CallbackReturn::Return)
}),
)
.unwrap();
ctx.state.registry.stash(&ctx, metatable)
}

Expand All @@ -351,6 +490,7 @@ pub fn world_metatable(ctx: Context) -> StaticTable {
let luadata = ctx.luadata();
let resources_metatable = luadata.table(ctx, resources_metatable);
let components_metatable = luadata.table(ctx, components_metatable);
let assets_metatable = luadata.table(ctx, assets_metatable);
metatable
.set(
ctx,
Expand All @@ -375,6 +515,7 @@ pub fn world_metatable(ctx: Context) -> StaticTable {

let resources_metatable = ctx.state.registry.fetch(&resources_metatable);
let components_metatable = ctx.state.registry.fetch(&components_metatable);
let assets_metatable = ctx.state.registry.fetch(&assets_metatable);

if let Value::String(key) = key {
match key.as_bytes() {
Expand All @@ -388,6 +529,11 @@ pub fn world_metatable(ctx: Context) -> StaticTable {
components.set_metatable(&ctx, Some(components_metatable));
stack.push_front(components.into());
}
b"assets" => {
let assets = AnyUserData::new_static(&ctx, this.clone());
assets.set_metatable(&ctx, Some(assets_metatable));
stack.push_front(assets.into());
}
_ => (),
}
}
Expand All @@ -404,7 +550,7 @@ pub fn world_metatable(ctx: Context) -> StaticTable {
pub fn schema_metatable(ctx: Context) -> StaticTable {
let metatable = Table::new(&ctx);
let luadata = ctx.luadata();
let ecsref_metatable = luadata.table(ctx, luaref_metatable);
let ecsref_metatable = luadata.table(ctx, ecsref_metatable);

metatable
.set(
Expand Down

0 comments on commit d811463

Please sign in to comment.