Add stable legion entity ids (GuidEntityAllocator)
This commit is contained in:
parent
fb140ce4b0
commit
64ce5b42c0
@ -28,6 +28,7 @@ crossbeam-channel = "0.4.2"
|
||||
derivative = "2.1"
|
||||
smallvec = "1.4"
|
||||
tracing = "0.1"
|
||||
rand = "0.7.2"
|
||||
metrics = { version = "0.12", optional = true }
|
||||
serde = { version = "1", optional = true }
|
||||
fxhash = "0.2"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
borrow::AtomicRefCell,
|
||||
cons::{ConsAppend, ConsFlatten},
|
||||
entity::{Entity, EntityAllocator},
|
||||
entity::{Entity, GuidEntityAllocator},
|
||||
filter::{ChunksetFilterData, Filter},
|
||||
storage::{Component, ComponentTypeId, Tag, TagTypeId},
|
||||
world::{
|
||||
@ -313,7 +313,7 @@ where
|
||||
pub struct CommandBuffer {
|
||||
world_id: WorldId,
|
||||
commands: AtomicRefCell<VecDeque<EntityCommand>>,
|
||||
entity_allocator: Arc<EntityAllocator>,
|
||||
entity_allocator: Arc<GuidEntityAllocator>,
|
||||
preallocated_capacity: usize,
|
||||
free_list: SmallVec<[Entity; 64]>,
|
||||
pending_insertion: SmallVec<[Entity; 64]>,
|
||||
|
||||
@ -7,7 +7,7 @@ use std::fmt::Display;
|
||||
use std::num::Wrapping;
|
||||
use std::ops::Deref;
|
||||
use std::ops::DerefMut;
|
||||
use std::sync::Arc;
|
||||
use std::{collections::HashSet, sync::Arc};
|
||||
|
||||
pub type EntityIndex = u32;
|
||||
pub(crate) type EntityVersion = Wrapping<u32>;
|
||||
@ -20,7 +20,7 @@ pub struct Entity {
|
||||
}
|
||||
|
||||
impl Entity {
|
||||
pub(crate) fn new(index: EntityIndex, version: EntityVersion) -> Entity {
|
||||
pub fn new(index: EntityIndex, version: EntityVersion) -> Entity {
|
||||
Entity { index, version }
|
||||
}
|
||||
|
||||
@ -247,6 +247,64 @@ impl DerefMut for Blocks {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { self.blocks.deref_mut() }
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct GuidEntityAllocator {
|
||||
entities: Arc<RwLock<HashSet<Entity>>>,
|
||||
next_ids: Arc<RwLock<Vec<Entity>>>,
|
||||
}
|
||||
|
||||
impl GuidEntityAllocator {
|
||||
pub fn is_alive(&self, entity: Entity) -> bool {
|
||||
self.entities.read().contains(&entity)
|
||||
}
|
||||
|
||||
pub fn push_next_ids(&self, ids: impl Iterator<Item = Entity>) {
|
||||
self.next_ids.write().extend(ids);
|
||||
}
|
||||
|
||||
/// Allocates a new unused `Entity` ID.
|
||||
pub fn create_entity(&self) -> Entity {
|
||||
if !self.next_ids.read().is_empty() {
|
||||
return self.next_ids.write().pop().unwrap();
|
||||
}
|
||||
|
||||
let entity = Entity::new(rand::random::<u32>(), Wrapping(1));
|
||||
self.entities.write().insert(entity);
|
||||
entity
|
||||
}
|
||||
|
||||
/// Creates an iterator which allocates new `Entity` IDs.
|
||||
pub fn create_entities(&self) -> GuidCreateEntityIter {
|
||||
GuidCreateEntityIter {
|
||||
allocator: self,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn delete_entity(&self, entity: Entity) -> bool {
|
||||
self.entities.write().remove(&entity)
|
||||
}
|
||||
|
||||
pub(crate) fn delete_all_entities(&self) {
|
||||
self.entities.write().clear();
|
||||
}
|
||||
|
||||
pub(crate) fn merge(&self, other: GuidEntityAllocator) {
|
||||
self.entities.write().extend(other.entities.write().drain())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GuidCreateEntityIter<'a> {
|
||||
allocator: &'a GuidEntityAllocator
|
||||
}
|
||||
|
||||
impl<'a> Iterator for GuidCreateEntityIter<'a> {
|
||||
type Item = Entity;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
Some(self.allocator.create_entity())
|
||||
}
|
||||
}
|
||||
|
||||
/// Manages the allocation and deletion of `Entity` IDs within a world.
|
||||
#[derive(Debug)]
|
||||
pub struct EntityAllocator {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
entity::{Entity, EntityAllocator},
|
||||
entity::{Entity, GuidEntityAllocator},
|
||||
index::{ArchetypeIndex, ChunkIndex, SetIndex},
|
||||
storage::{
|
||||
ArchetypeData, ArchetypeDescription, Chunkset, ComponentMeta, ComponentTypeId, TagMeta,
|
||||
@ -78,7 +78,7 @@ pub trait WorldDeserializer {
|
||||
fn deserialize_entities<'de, D: Deserializer<'de>>(
|
||||
&self,
|
||||
deserializer: D,
|
||||
entity_allocator: &EntityAllocator,
|
||||
entity_allocator: &GuidEntityAllocator,
|
||||
entities: &mut Vec<Entity>,
|
||||
) -> Result<(), <D as Deserializer<'de>>::Error>;
|
||||
}
|
||||
|
||||
@ -2,9 +2,8 @@ use crate::borrow::Ref;
|
||||
use crate::borrow::RefMut;
|
||||
use crate::entity::BlockAllocator;
|
||||
use crate::entity::Entity;
|
||||
use crate::entity::EntityAllocator;
|
||||
use crate::entity::EntityLocation;
|
||||
use crate::entity::Locations;
|
||||
use crate::entity::{GuidEntityAllocator, Locations};
|
||||
use crate::event::Event;
|
||||
use crate::filter::ArchetypeFilterData;
|
||||
use crate::filter::ChunksetFilterData;
|
||||
@ -75,7 +74,7 @@ impl Universe {
|
||||
/// unique `Entity` IDs, even across worlds. See also `World::new`.
|
||||
pub fn create_world(&self) -> World {
|
||||
let id = WorldId::next(self.id.0);
|
||||
let world = World::new_in_universe(id, EntityAllocator::new(self.allocator.clone()));
|
||||
let world = World::new_in_universe(id, GuidEntityAllocator::default());
|
||||
|
||||
info!(universe = self.id.0, world = world.id().1, "Created world");
|
||||
world
|
||||
@ -99,7 +98,7 @@ impl WorldId {
|
||||
pub struct World {
|
||||
id: WorldId,
|
||||
storage: UnsafeCell<Storage>,
|
||||
pub(crate) entity_allocator: Arc<EntityAllocator>,
|
||||
pub(crate) entity_allocator: Arc<GuidEntityAllocator>,
|
||||
entity_locations: Locations,
|
||||
defrag_progress: usize,
|
||||
command_buffer_size: usize,
|
||||
@ -120,11 +119,11 @@ impl World {
|
||||
pub fn new() -> Self {
|
||||
Self::new_in_universe(
|
||||
WorldId::next(0),
|
||||
EntityAllocator::new(Arc::new(Mutex::new(BlockAllocator::new()))),
|
||||
GuidEntityAllocator::default(),
|
||||
)
|
||||
}
|
||||
|
||||
fn new_in_universe(id: WorldId, allocator: EntityAllocator) -> Self {
|
||||
fn new_in_universe(id: WorldId, allocator: GuidEntityAllocator) -> Self {
|
||||
Self {
|
||||
id,
|
||||
storage: UnsafeCell::new(Storage::new(id)),
|
||||
|
||||
@ -22,6 +22,7 @@ Here are the changes made:
|
||||
* ResourceTypeId, ComponentTypeId, TagTypeId use static str (std::any::type_name) instead of TypeId (std::any::TypeId is not constant across rust binaries)
|
||||
* Implement "DowncastTypeName" to allow downcasting based on type name
|
||||
* Upgraded derivative, smallvec, itertools to eliminate redundant dependencies
|
||||
* Added GuidEntityAllocator. Generates random entityids and enables "stable" ids across serialization.
|
||||
|
||||
## Benchmarks
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user