add gear allocator
authoralfadur
Thu, 25 Jul 2019 22:31:24 +0300 (2019-07-25)
changeset 15295 42b710b0f883
parent 15294 bfd185ad03e7
child 15296 66c987015f2d
add gear allocator
rust/hwphysics/src/collision.rs
rust/hwphysics/src/common.rs
rust/hwphysics/src/grid.rs
rust/hwphysics/src/lib.rs
rust/hwphysics/src/physics.rs
rust/hwphysics/src/time.rs
rust/lib-hedgewars-engine/src/world.rs
--- a/rust/hwphysics/src/collision.rs	Thu Jul 25 21:59:20 2019 +0300
+++ b/rust/hwphysics/src/collision.rs	Thu Jul 25 22:31:24 2019 +0300
@@ -147,4 +147,8 @@
     fn add(&mut self, gear_id: GearId, gear_data: CollisionData) {
         self.grid.insert_static(gear_id, &gear_data.bounds);
     }
+
+    fn remove(&mut self, gear_id: GearId) {
+        self.grid.remove(gear_id);
+    }
 }
--- a/rust/hwphysics/src/common.rs	Thu Jul 25 21:59:20 2019 +0300
+++ b/rust/hwphysics/src/common.rs	Thu Jul 25 22:31:24 2019 +0300
@@ -1,10 +1,40 @@
-pub type GearId = std::num::NonZeroU16;
+use std::{collections::BinaryHeap, num::NonZeroU16};
+
+pub type GearId = NonZeroU16;
 pub trait GearData {}
 
 pub trait GearDataProcessor<T: GearData> {
     fn add(&mut self, gear_id: GearId, gear_data: T);
+    fn remove(&mut self, gear_id: GearId);
 }
 
 pub trait GearDataAggregator<T: GearData> {
     fn find_processor(&mut self) -> &mut GearDataProcessor<T>;
 }
+
+pub struct GearAllocator {
+    max_id: u16,
+    free_ids: BinaryHeap<GearId>,
+}
+
+impl GearAllocator {
+    pub fn new() -> Self {
+        Self {
+            max_id: 0,
+            free_ids: BinaryHeap::with_capacity(1024),
+        }
+    }
+
+    pub fn alloc(&mut self) -> Option<GearId> {
+        self.free_ids.pop().or_else(|| {
+            self.max_id.checked_add(1).and_then(|new_max_id| {
+                self.max_id = new_max_id;
+                NonZeroU16::new(new_max_id)
+            })
+        })
+    }
+
+    pub fn free(&mut self, gear_id: GearId) {
+        self.free_ids.push(gear_id)
+    }
+}
--- a/rust/hwphysics/src/grid.rs	Thu Jul 25 21:59:20 2019 +0300
+++ b/rust/hwphysics/src/grid.rs	Thu Jul 25 22:31:24 2019 +0300
@@ -71,6 +71,8 @@
         bin.dynamic_entries.push(*bounds);
     }
 
+    pub fn remove(&mut self, gear_id: GearId) {}
+
     pub fn update_position(
         &mut self,
         gear_id: GearId,
--- a/rust/hwphysics/src/lib.rs	Thu Jul 25 21:59:20 2019 +0300
+++ b/rust/hwphysics/src/lib.rs	Thu Jul 25 22:31:24 2019 +0300
@@ -10,7 +10,7 @@
 
 use crate::{
     collision::{CollisionData, CollisionProcessor, ContactData},
-    common::{GearData, GearDataAggregator, GearDataProcessor, GearId},
+    common::{GearAllocator, GearData, GearDataAggregator, GearDataProcessor, GearId},
     physics::{PhysicsData, PhysicsProcessor},
     time::TimeProcessor,
 };
@@ -23,6 +23,7 @@
 }
 
 pub struct World {
+    allocator: GearAllocator,
     physics: PhysicsProcessor,
     collision: CollisionProcessor,
     time: TimeProcessor,
@@ -44,12 +45,26 @@
 impl World {
     pub fn new(world_size: Size) -> Self {
         Self {
+            allocator: GearAllocator::new(),
             physics: PhysicsProcessor::new(),
             collision: CollisionProcessor::new(world_size),
             time: TimeProcessor::new(),
         }
     }
 
+    #[inline]
+    pub fn new_gear(&mut self) -> Option<GearId> {
+        self.allocator.alloc()
+    }
+
+    #[inline]
+    pub fn delete_gear(&mut self, gear_id: GearId) {
+        self.physics.remove(gear_id);
+        self.collision.remove(gear_id);
+        self.time.cancel(gear_id);
+        self.allocator.free(gear_id)
+    }
+
     pub fn step(&mut self, time_step: FPNum, land: &Land2D<u32>) {
         let updates = self.physics.process(time_step);
         let collision = self.collision.process(land, &updates);
--- a/rust/hwphysics/src/physics.rs	Thu Jul 25 21:59:20 2019 +0300
+++ b/rust/hwphysics/src/physics.rs	Thu Jul 25 22:31:24 2019 +0300
@@ -35,12 +35,20 @@
         self.gear_ids.len()
     }
 
-    fn push(&mut self, id: GearId, physics: PhysicsData) {
-        self.gear_ids.push(id);
+    fn push(&mut self, gear_id: GearId, physics: PhysicsData) {
+        self.gear_ids.push(gear_id);
         self.positions.push(physics.position);
         self.velocities.push(physics.velocity);
     }
 
+    fn remove(&mut self, gear_id: GearId) {
+        if let Some(index) = self.gear_ids.iter().position(|id| *id == gear_id) {
+            self.gear_ids.swap_remove(index);
+            self.positions.swap_remove(index);
+            self.velocities.swap_remove(index);
+        }
+    }
+
     fn iter_pos_update(&mut self) -> impl Iterator<Item = (GearId, (&mut FPPoint, &FPPoint))> {
         self.gear_ids
             .iter()
@@ -66,6 +74,13 @@
         self.gear_ids.push(gear_id);
         self.positions.push(physics.position);
     }
+
+    fn remove(&mut self, gear_id: GearId) {
+        if let Some(index) = self.gear_ids.iter().position(|id| *id == gear_id) {
+            self.gear_ids.swap_remove(index);
+            self.positions.swap_remove(index);
+        }
+    }
 }
 
 pub struct PhysicsProcessor {
@@ -149,4 +164,9 @@
             self.dynamic_physics.push(gear_id, gear_data);
         }
     }
+
+    fn remove(&mut self, gear_id: GearId) {
+        self.static_physics.remove(gear_id);
+        self.dynamic_physics.remove(gear_id)
+    }
 }
--- a/rust/hwphysics/src/time.rs	Thu Jul 25 21:59:20 2019 +0300
+++ b/rust/hwphysics/src/time.rs	Thu Jul 25 22:31:24 2019 +0300
@@ -79,6 +79,8 @@
         event_id
     }
 
+    pub fn cancel(&mut self, gear_id: GearId) {}
+
     pub fn process(&mut self, time_step: FPNum) -> &OccurredEvents {
         self.timeouts.clear();
         self.current_time += time_step;
--- a/rust/lib-hedgewars-engine/src/world.rs	Thu Jul 25 21:59:20 2019 +0300
+++ b/rust/lib-hedgewars-engine/src/world.rs	Thu Jul 25 22:31:24 2019 +0300
@@ -28,7 +28,6 @@
     map_renderer: Option<MapRenderer>,
     gear_renderer: Option<GearRenderer>,
     camera: Camera,
-    last_gear_id: GearId,
 }
 
 impl World {
@@ -40,7 +39,6 @@
             map_renderer: None,
             gear_renderer: None,
             camera: Camera::new(),
-            last_gear_id: std::num::NonZeroU16::new(1).unwrap(),
         }
     }
 
@@ -128,15 +126,9 @@
         }
     }
 
-    fn get_unused_gear_id(&mut self) -> GearId {
-        let id = self.last_gear_id;
-        self.last_gear_id = std::num::NonZeroU16::new(self.last_gear_id.get() + 1).unwrap();
-        id
-    }
-
     fn create_gear(&mut self, position: Point) {
-        let id = self.get_unused_gear_id();
         if let Some(ref mut state) = self.game_state {
+            let id = state.physics.new_gear().unwrap();
             let fp_position = FPPoint::new(position.x.into(), position.y.into());
             state.physics.add_gear_data(
                 id,