engine, ecs: add lazy entity building
parent
a338a43195
commit
dd543f83f2
|
@ -29,6 +29,7 @@ end
|
|||
|
||||
function Test:tick()
|
||||
print("tick! " .. tostring(self.val))
|
||||
print("components " .. tostring(self.components))
|
||||
end
|
||||
|
||||
sent.register("Test", Test)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue