engine, ecs: add lazy entity building

master
q3k 2021-04-06 11:25:52 +00:00
parent a338a43195
commit dd543f83f2
4 changed files with 106 additions and 23 deletions

View File

@ -29,6 +29,7 @@ end
function Test:tick()
print("tick! " .. tostring(self.val))
print("components " .. tostring(self.components))
end
sent.register("Test", Test)

View File

@ -9,19 +9,6 @@ fn debug_str(v: &mlua::Value) -> String {
}
}
pub struct WorldContext {
// TODO(q3k): this leaks memory, right?
lua: &'static mlua::Lua,
classes: Arc<Mutex<BTreeMap<String, ScriptedEntityClass>>>,
instances: Arc<Mutex<InstanceData>>,
}
#[derive(Debug)]
struct InstanceData {
ecs: BTreeMap<ecs::EntityID, ScriptedEntity>,
queue: Vec<ScriptedEntity>,
}
#[derive(Debug)]
struct ScriptedEntityClass {
name: String,
@ -46,7 +33,6 @@ struct ScriptedEntity {
#[derive(Debug)]
struct ScriptedEntityID {
ecs_id: Option<ecs::EntityID>,
internal_id: u64,
}
impl mlua::UserData for ScriptedEntityID {}
@ -63,6 +49,20 @@ impl ScriptedEntity {
}
}
pub struct WorldContext {
// TODO(q3k): this leaks memory, right?
lua: &'static mlua::Lua,
classes: Arc<Mutex<BTreeMap<String, ScriptedEntityClass>>>,
instances: Arc<Mutex<InstanceData>>,
}
#[derive(Debug)]
struct InstanceData {
ecs: BTreeMap<ecs::EntityID, ScriptedEntity>,
internal_to_ecs: BTreeMap<u64, ecs::EntityID>,
queue: Vec<ScriptedEntity>,
}
impl WorldContext {
pub fn new(world: &ecs::World) -> Self {
let lua = mlua::Lua::new().into_static();
@ -76,6 +76,7 @@ impl WorldContext {
let classes = Arc::new(Mutex::new(BTreeMap::new()));
let instances = Arc::new(Mutex::new(InstanceData {
ecs: BTreeMap::new(),
internal_to_ecs: BTreeMap::new(),
queue: Vec::new(),
}));
@ -122,14 +123,41 @@ impl WorldContext {
};
let cls: mlua::Table = lua.registry_value(&sec.table)?;
// (meta)table tree for entity objects:
//
// table: { }
// | metatable
// V
// metatable: { __index }
// |
// .-------------'
// V
// dispatch: { components.{...}, ... }
// | metadata
// V
// metametatable: { __index }
// |
// .-----------------'
// V
// cls: { init, tick, ... }
let table = lua.create_table()?;
let meta = lua.create_table()?;
meta.set("__index", cls)?;
table.set_metatable(Some(meta));
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)?;
let components = lua.create_table()?;
dispatch.set("components", components.clone());
let components_meta = lua.create_table()?;
components.set_metatable(Some(components_meta));
let sent = ScriptedEntity::new(secid.name.clone(), lua.create_registry_value(table.clone())?);
table.set("__sent_id", ScriptedEntityID {
ecs_id: sent.ecs_id,
internal_id: sent.internal_id,
});
instances.lock().unwrap().queue.push(sent);
@ -156,5 +184,18 @@ impl WorldContext {
impl <'system> ecs::System<'system> for WorldContext {
type SystemData = ecs::ReadWriteAll<'system>;
fn run(&mut self, sd: Self::SystemData) {
let mut instances = self.instances.lock().unwrap();
// Lazily create enqueued entities.
if instances.queue.len() > 0 {
let mut queue = std::mem::replace(&mut instances.queue, Vec::new());
for mut el in queue.into_iter() {
let ecsid = sd.new_entity_lazy().build(&sd);
el.ecs_id = Some(ecsid);
instances.internal_to_ecs.insert(el.internal_id, ecsid);
log::debug!("Created sent of type {} with ECS ID {} and internal ID {}", el.class_name, ecsid, el.internal_id);
instances.ecs.insert(ecsid, el);
}
}
}
}

View File

@ -34,3 +34,29 @@ impl<'a> EntityBuilder<'a> {
self.ent.id()
}
}
pub struct LazyEntityBuilder {
components: Vec<(component::ID, Box<dyn component::Component>)>,
ent: Entity,
}
impl LazyEntityBuilder {
pub fn new(id: ID) -> Self {
Self {
components: Vec::new(),
ent: Entity(id),
}
}
pub fn with<T: component::Component>(mut self, c: T) -> Self {
self.components.push((component::component_id::<T>(), Box::new(c)));
self
}
pub fn build(self, w: &world::World) -> ID {
for (cid, c) in self.components.into_iter() {
w.enqueue_register_component_entity(cid, c, self.ent);
}
self.ent.id()
}
}

View File

@ -140,7 +140,13 @@ pub struct ReadWriteAll<'a> {
world: &'a World,
}
impl<'a> ReadWriteAll<'a> {
impl<'a> ReadWriteAll<'a> {}
impl<'a> std::ops::Deref for ReadWriteAll<'a> {
type Target = World;
fn deref(&self) -> &Self::Target {
self.world
}
}
@ -150,7 +156,7 @@ pub struct World {
component_lua_bindings: BTreeMap<component::ID, Box<dyn component::LuaBindings>>,
component_queue: RefCell<Vec<(component::ID, Box<dyn component::Component>, entity::Entity)>>,
globals: GlobalMap,
next_id: entity::ID,
next_id: RefCell<entity::ID>,
}
impl World {
@ -161,14 +167,23 @@ impl World {
component_lua_bindings: BTreeMap::new(),
component_queue: RefCell::new(Vec::new()),
globals: GlobalMap::new(),
next_id: 1u64,
next_id: RefCell::new(1u64),
}
}
fn allocate_next_id(&self) -> entity::ID {
let res = self.next_id.borrow().clone();
let mut nid = self.next_id.borrow_mut();
*nid = *nid + 1;
res
}
pub fn new_entity(&mut self) -> entity::EntityBuilder {
let id = self.next_id;
self.next_id += 1;
entity::EntityBuilder::new(self, id)
entity::EntityBuilder::new(self, self.allocate_next_id())
}
pub fn new_entity_lazy(&self) -> entity::LazyEntityBuilder {
entity::LazyEntityBuilder::new(self.allocate_next_id())
}
pub fn register_component_entity(