Skip to content

Commit

Permalink
Implement instance_destroy with copy-on-write entity lists
Browse files Browse the repository at this point in the history
  • Loading branch information
rpjohnst committed May 23, 2020
1 parent 104da50 commit be4f276
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 17 deletions.
24 changes: 22 additions & 2 deletions engine/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::motion;
pub struct State {
pub next_id: i32,
pub instances: vm::EntityMap<Instance>,
pub destroyed: Vec<vm::Entity>,
}

pub struct Instance {
Expand All @@ -16,7 +17,8 @@ impl Default for State {
fn default() -> Self {
State {
next_id: 100001,
instances: Default::default(),
instances: vm::EntityMap::default(),
destroyed: Vec::default(),
}
}
}
Expand Down Expand Up @@ -106,12 +108,30 @@ impl State {

let persistent = false;

let entity = world.create_instance(obj, id);
let entity = world.create_entity(object_index, id);
let instance = Instance { object_index, id, persistent };
self.instances.insert(entity, instance);
let instance = motion::Instance::from_pos(x, y);
motion.instances.insert(entity, instance);

Ok(id)
}

#[gml::function]
pub fn instance_destroy(&mut self, world: &mut vm::World, entity: vm::Entity) {
let &Instance { object_index, id, .. } = match self.instances.get(entity) {
Some(instance) => instance,
None => return,
};
world.remove_entity(object_index, id, entity);
self.destroyed.push(entity);
}

pub fn free_destroyed(&mut self, world: &mut vm::World, motion: &mut motion::State) {
for entity in self.destroyed.drain(..) {
motion.instances.remove(entity);
self.instances.remove(entity);
world.destroy_entity(entity);
}
}
}
16 changes: 16 additions & 0 deletions gml/src/vm/entity_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,22 @@ impl<T> EntityMap<T> {
old
}

pub fn remove(&mut self, entity: Entity) -> Option<T> {
if entity.index() >= self.data.len() {
return None;
}

let entry = &mut self.data[entity.index()];
let equal = entry.as_ref()
.map(move |&Entry { generation, .. }| entity.generation() == generation)
.unwrap_or(false);
if !equal {
return None;
}

entry.take().map(|Entry { value, .. }| value)
}

pub fn contains_key(&self, entity: Entity) -> bool {
self.get(entity).is_some()
}
Expand Down
9 changes: 9 additions & 0 deletions gml/src/vm/instance_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ impl<K, V> InstanceMap<K, V> where K: Eq + Hash, V: Clone {
}
}
}

pub fn remove(&mut self, key: K) -> Option<V> {
let index = self.keys.remove(&key)?;
let value = self.values.remove(index);
for index in self.keys.values_mut().filter(|&&mut i| i > index) {
*index -= 1;
}
Some(value)
}
}

impl<K, V> Index<K> for InstanceMap<K, V> where K: Eq + Hash {
Expand Down
18 changes: 17 additions & 1 deletion gml/src/vm/world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,29 @@ impl Default for World {
}

impl World {
pub fn create_instance(&mut self, object_index: i32, id: i32) -> vm::Entity {
pub fn create_entity(&mut self, object_index: i32, id: i32) -> vm::Entity {
let entity = self.entities.create();
self.members.insert(entity, HashMap::default());
self.objects.entry(object_index).or_default().push(entity);
self.instances.insert(id, entity);
entity
}

// Remove an instance from the world, but retain its entity, to be destroyed or re-added later.
pub fn remove_entity(&mut self, object_index: i32, id: i32, entity: vm::Entity) {
self.instances.remove(id);

if let Some(object_instances) = self.objects.get_mut(&object_index) {
if let Some(position) = object_instances.iter().position(move |&e| e == entity) {
object_instances.remove(position);
}
}
}

pub fn destroy_entity(&mut self, entity: vm::Entity) {
self.members.remove(entity);
self.entities.destroy(entity);
}
}

pub trait Api {
Expand Down
2 changes: 1 addition & 1 deletion gml/tests/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ impl Engine {
let id = self.next_id;
self.next_id += 1;

(id, self.world.create_instance(0, id))
(id, self.world.create_entity(0, id))
}

fn get_global_scalar(&mut self, _: vm::Entity, _: usize) -> vm::Value {
Expand Down
34 changes: 21 additions & 13 deletions runner/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,28 @@ fn main() {
show_debug_message("grid[# 1, 1] =", ds_grid_get(grid, 1, 1))
ds_grid_destroy(grid)
show_debug_message("object_index =", object_index)
show_debug_message("id =", id)
persistent = true
show_debug_message("persistent =", persistent)
repeat (2) {
show_debug_message()
show_debug_message("object_index =", object_index)
show_debug_message("id =", id)
persistent = true
show_debug_message("persistent =", persistent)
for (i = 0; i < instance_count; i += 1) {
if instance_exists(instance_id[i]) {
show_debug_message(instance_id[i], "=>", instance_id[i].object_index)
for (i = 0; i < instance_count; i += 1) {
if instance_exists(instance_id[i]) {
show_debug_message(instance_id[i], "=>", instance_id[i].object_index)
}
}
}
show_debug_message("instance_find(1, 0) =>", instance_find(1, 0))
show_debug_message("instance_exists(0) =>", instance_exists(0))
show_debug_message("instance_exists(100002) =>", instance_exists(100002))
show_debug_message("instance_exists(2) =>", instance_exists(2))
show_debug_message("instance_number(1) =>", instance_number(1))
show_debug_message("instance_find(1, 0) =>", instance_find(1, 0))
show_debug_message("instance_exists(0) =>", instance_exists(0))
show_debug_message("instance_exists(id) =>", instance_exists(id))
show_debug_message("instance_exists(100002) =>", instance_exists(100002))
show_debug_message("instance_exists(2) =>", instance_exists(2))
show_debug_message("instance_number(1) =>", instance_number(1))
instance_destroy()
}
}"#));

let resources = gml::build(&items).unwrap_or_else(|_| panic!());
Expand All @@ -83,4 +89,6 @@ fn main() {
let span = Span { low: location as usize, high: location as usize };
errors.error(span, &format!("{}", error.kind));
}

engine.instance.free_destroyed(&mut engine.world, &mut engine.motion);
}

0 comments on commit be4f276

Please sign in to comment.