engine: rewrite component metatable setup to lua

master
q3k 2021-04-08 22:39:11 +00:00
parent 9c2c2c1f3c
commit 1553bdce9b
2 changed files with 40 additions and 85 deletions

View File

@ -1,10 +1,4 @@
sent = {}
sent.newindex = function(t, k, v)
return __sent_components_newindex(t, k, v)
end
sent.index = function(t, k)
return __sent_components_index(t, k)
end
sent.register = function (cfg)
if cfg.name == nil then
error("sent.register: needs name")
@ -32,11 +26,35 @@ sent.register = function (cfg)
cls.__sent_class_id = sent_class_id
cls.new = function(...)
local arg = {...}
local res = __sent_new(sent_class_id)
if res.init ~= nil then
res:init(unpack(arg))
-- Make object table, instantiate with runtime.
local table = {}
local sent_id = __sent_new(table, sent_class_id)
table.__sent_id = sent_id
-- Configure components dispatcher.
table.components = {}
table.components.__sent_id = sent_id
local components_meta = {}
components_meta.__index = function(t, k)
return __sent_components_index(t, k)
end
return res
components_meta.__newindex = function(t, k, v)
return __sent_components_newindex(t, k, v)
end
setmetatable(table.components, components_meta)
-- Make table deref via table to class.
local metatable = {}
metatable.__index = cls
setmetatable(table, metatable)
-- Call initializer, if present.
if table.init ~= nil then
table:init(unpack(arg))
end
return table
end
end

View File

@ -52,14 +52,12 @@ struct ScriptedEntity {
internal_id: u64,
status: ScriptedEntityStatus,
table: mlua::RegistryKey,
cls: mlua::RegistryKey,
}
impl ScriptedEntity {
fn new(
class_name: String,
table: mlua::RegistryKey,
cls: mlua::RegistryKey,
components: BTreeMap<String, Box<dyn ecs::Component>>,
) -> Self {
let internal_id = GLOBAL_SCRIPTED_ENTITY_ID.fetch_add(1, atomic::Ordering::SeqCst) + 1;
@ -68,69 +66,8 @@ impl ScriptedEntity {
internal_id,
status: ScriptedEntityStatus::QueuedForCreation(components),
table,
cls,
}
}
fn set_metatable(
&self,
lua: &mlua::Lua,
world: &ecs::World,
) -> mlua::Result<()>
{
// (meta)table tree for entity objects:
//
// table: { }
// | metatable
// V
// metatable: { __index }
// |
// .-------------'
// V
// dispatch: { components.{...}, ... }
// | metadata
// V
// metametatable: { __index }
// |
// .-----------------'
// V
// cls: { init, tick, ... }
let table: mlua::Table = lua.registry_value(&self.table)?;
let cls: mlua::Table = lua.registry_value(&self.cls)?;
let meta = lua.create_table()?;
let dispatch = lua.create_table()?;
let metameta = lua.create_table()?;
table.set_metatable(Some(meta.clone()));
meta.set("__index", dispatch.clone())?;
dispatch.set_metatable(Some(metameta.clone()));
metameta.set("__index", cls)?;
table.set("__sent_id", ScriptedEntityID {
internal_id: self.internal_id,
});
let components = lua.create_table()?;
dispatch.set("components", components.clone())?;
let componentsmeta = lua.create_table()?;
componentsmeta.set(
"__index",
lua.globals().get::<_, mlua::Table>("sent")?.get::<_, mlua::Function>("index")?,
)?;
componentsmeta.set(
"__newindex",
lua.globals().get::<_, mlua::Table>("sent")?.get::<_, mlua::Function>("newindex")?,
)?;
components.set_metatable(Some(componentsmeta));
components.raw_set("__sent_id", ScriptedEntityID {
internal_id: self.internal_id,
});
Ok(())
}
}
#[derive(Debug, Clone)]
@ -465,32 +402,31 @@ impl WorldContext {
{
let classes = self.classes.clone();
let instances = self.instances.clone();
globals.set("__sent_new", scope.create_function(move |lua, args: mlua::AnyUserData| {
globals.set("__sent_new", scope.create_function(move |lua, args: (mlua::Table, mlua::AnyUserData)| {
let classes = classes.lock().unwrap();
let secid = args.borrow::<ScriptedEntityClassID>()?;
let table = args.0;
let secid = args.1.borrow::<ScriptedEntityClassID>()?;
let sec = match classes.get(&secid.name) {
Some(el) => el,
None => return Err(RuntimeError(format!("lost secid {:?}", secid.name))),
};
let cls: mlua::Table = lua.registry_value(&sec.cls)?;
let table = lua.create_table()?;
let components: BTreeMap<String, Box<dyn ecs::Component>> = sec.components.iter().map(|(k, v)| {
(k.clone(), v.clone_dyn())
}).collect();
let sent = ScriptedEntity::new(
secid.name.clone(),
lua.create_registry_value(table.clone())?,
lua.create_registry_value(cls.clone())?,
components,
);
sent.set_metatable(lua, world)?;
let seid = ScriptedEntityID {
internal_id: sent.internal_id,
};
instances.write().unwrap().queue.push(sent);
Ok(table)
Ok(seid)
})?)?;
}
@ -556,7 +492,7 @@ where
self.scope_resourcemanager(scope, world)?;
self.scope_time(scope, world)?;
// Copy out functions refs to release lock.
let mut to_run: Vec<(ecs::EntityID, mlua::Function)> = vec![];
let mut tickers: Vec<(ecs::EntityID, mlua::Function)> = vec![];
{
let instances = instances.read().unwrap();
for (ecsid, sent) in instances.ecs.iter() {
@ -581,10 +517,11 @@ where
continue;
},
};
to_run.push((*ecsid, cb));
tickers.push((*ecsid, cb));
}
}
for (ecsid, cb) in to_run.into_iter() {
for (ecsid, cb) in tickers.into_iter() {
match cb.call::<mlua::Value, mlua::Value>(mlua::Value::Nil) {
Ok(_) => (),
Err(err) => {