bones_scripting/lua/bindings/
components.rs

1use super::*;
2
3pub fn metatable(ctx: Context) -> Table {
4    let metatable = Table::new(&ctx);
5    metatable
6        .set(
7            ctx,
8            "__tostring",
9            Callback::from_fn(&ctx, |ctx, _fuel, mut stack| {
10                stack.push_front(
11                    piccolo::String::from_static(&ctx, "Components { insert, remove, get }").into(),
12                );
13                Ok(CallbackReturn::Return)
14            }),
15        )
16        .unwrap();
17    metatable
18        .set(ctx, "__newindex", ctx.singletons().get(ctx, no_newindex))
19        .unwrap();
20
21    let get_callback = ctx.registry().stash(
22        &ctx,
23        Callback::from_fn(&ctx, |ctx, _fuel, mut stack| {
24            let (world, entity_ecsref, schema): (&WorldRef, &EcsRef, UserData) =
25                stack.consume(ctx)?;
26
27            let b = entity_ecsref.borrow();
28            let entity = *b.schema_ref()?.try_cast::<Entity>()?;
29
30            let schema = *schema.downcast_static::<&Schema>()?;
31
32            let store = world.with(|world| {
33                let store = world.components.get_cell_by_schema(schema);
34                Ok::<_, anyhow::Error>(store)
35            })?;
36
37            let ecsref = EcsRef {
38                data: EcsRefData::Component(ComponentRef { store, entity }),
39                path: default(),
40            };
41
42            // Return nil if the component is not present
43            if ecsref.borrow().schema_ref().is_err() {
44                stack.replace(ctx, Value::Nil);
45                return Ok(CallbackReturn::Return);
46            }
47
48            let ecsref = ecsref.into_value(ctx);
49            stack.replace(ctx, ecsref);
50
51            Ok(CallbackReturn::Return)
52        }),
53    );
54    let insert_callback = ctx.registry().stash(
55        &ctx,
56        Callback::from_fn(&ctx, |ctx, _fuel, mut stack| {
57            let (world, entity_ecsref, value_ecsref): (&WorldRef, &EcsRef, &EcsRef) =
58                stack.consume(ctx)?;
59
60            let b = entity_ecsref.borrow();
61            let entity = *b.schema_ref()?.try_cast::<Entity>()?;
62
63            let value = {
64                let b = value_ecsref.borrow();
65                let value = b.schema_ref()?;
66                value.clone_into_box()
67            };
68
69            world.with(|world| {
70                let store = world.components.get_by_schema(value.schema());
71                let mut store = store.borrow_mut();
72                store.insert_box(entity, value);
73                Ok::<_, anyhow::Error>(())
74            })?;
75
76            Ok(CallbackReturn::Return)
77        }),
78    );
79    let remove_callback = ctx.registry().stash(
80        &ctx,
81        Callback::from_fn(&ctx, |ctx, _fuel, mut stack| {
82            let (world, entity_ecsref, schema): (&WorldRef, &EcsRef, UserData) =
83                stack.consume(ctx)?;
84
85            let b = entity_ecsref.borrow();
86            let entity = *b.schema_ref()?.try_cast::<Entity>()?;
87
88            let schema = *schema.downcast_static::<&Schema>()?;
89
90            world.with(|world| {
91                let store = world.components.get_by_schema(schema);
92                let mut store = store.borrow_mut();
93                store.remove_box(entity);
94                Ok::<_, anyhow::Error>(())
95            })?;
96
97            Ok(CallbackReturn::Return)
98        }),
99    );
100
101    metatable
102        .set(
103            ctx,
104            "__index",
105            Callback::from_fn(&ctx, move |ctx, _fuel, mut stack| {
106                let (_world, key): (&WorldRef, lua::Value) = stack.consume(ctx)?;
107
108                if let Value::String(key) = key {
109                    #[allow(clippy::single_match)]
110                    match key.as_bytes() {
111                        b"get" => {
112                            stack.push_front(ctx.registry().fetch(&get_callback).into());
113                        }
114                        b"insert" => {
115                            stack.push_front(ctx.registry().fetch(&insert_callback).into());
116                        }
117                        b"remove" => {
118                            stack.push_front(ctx.registry().fetch(&remove_callback).into());
119                        }
120                        _ => (),
121                    }
122                }
123
124                Ok(CallbackReturn::Return)
125            }),
126        )
127        .unwrap();
128
129    metatable
130}