use std::{sync::atomic::{AtomicUsize, Ordering}};
use crate::{
Bitmask, EntitiesExt, NodePtr, NodePtrMut, Ptr, PtrMut, Sto, StorageRef, StorageRegistry,
creation_context::CreationContextExt,
entity::EntitiesStorage,
operators::{
EntitiesComponentIter, ReadOnlyOp, ReadOnlyOrderedOp, ChangedDataSend, EntitiesData,
OrderedData, OrderedDataSend, UnorderedData, UnorderedDataSend
},
resource::{ResourcesCreation, ResourcesExt, ResourcesThreadLocalExt},
storage::{FastIndexExt, ReadOnlyStorage},
sync::{IndexGuard, LazyIndexGuard, OrderedIndexGuard, StorageWriteGuard},
systems::{
self, Systems, Priority, AnySystem, StatsType, SystemConditionElse,
SystemConditionSend, SystemConditionThreadLocal, SystemConditionCreation,
CreationSystemOnce, SystemConditionSendOnce, SystemConditionThreadLocalOnce,
SystemConditionCreationOnce,
CreationSystem, System, SystemThreadLocal, SystemOnce, SystemOnceThreadLocal
}, utils::{IntoEntitiesIterator}};
#[cfg(feature="parallel_systems")]
use crate::utils::delete_lifetime;
#[cfg(feature = "async")]
use systems::CreationSystemAsync;
use crate::sync::{WriteGuardRef, ReadGuardRef};
use crate::resource::{Resources, ResourcesThreadLocal};
use crate::component::{
ComponentSend, Component, ComponentThreadLocal, OneToNComponentSend, OneToNComponentThreadLocal,
};
use crate::entity::{
Entity, EntityBuilder, Entities, EntitiesThreadLocal, EntitiesCreation
};
use crate::bitmask::{self, MaskType};
use crate::operators::OperatorId;
use crate::storage::{Storage, OneToNStorage, CreationSto};
#[cfg(feature="dynamic_systems")]
use crate::dynamic_system_loader::DynamicSystemsLoader;
#[cfg(feature="debug_parameters")]
use crate::debug::SystemDebug;
#[cfg(feature="stats_events")]
use seitan::*;
use crate::resource::ResourcesContainer;
use std::path::Path;
#[cfg(any(feature="parallel_systems", feature = "async"))]
use std::mem;
use crate::systems::PredecessorsCache;
use crate::storage::{Storages, HierarchicalStorage};
use std::cell::UnsafeCell;
#[cfg(feature="parallel_systems")]
use crate::systems::SystemHandle;
#[cfg(feature="stats_events")]
use crate::utils::{time, Stat, thread_id};
#[cfg(all(feature="stats_events", feature="glin"))]
use std::time::Duration;
#[cfg(feature="dynamic_systems")]
use crate::DynamicSymbol;
#[cfg(feature="dynamic_systems")]
use crate::dynamic_system_loader::DynamicFunction;
use std::any::TypeId;
#[cfg(feature="debug_parameters")]
use crate::debug::EntitiesDebug;
use crate::DebugParameter;
pub struct World{
storages: Storages,
next_guid: AtomicUsize,
resources: ResourcesContainer,
systems: Systems,
priority_queue: Vec<(Priority, OperatorId)>,
predecessors_cache: PredecessorsCache,
#[cfg(feature="parallel_systems")]
done_tx: crossbeam::channel::Sender<Result<SystemHandle, SystemHandle>>,
#[cfg(feature="parallel_systems")]
done_rx: crossbeam::channel::Receiver<Result<SystemHandle, SystemHandle>>,
#[cfg(feature="stats_events")]
total_duration: Property<'static, Stat>,
#[cfg(feature="dynamic_systems")]
dynamic_systems: DynamicSystemsLoader,
#[cfg(feature="parallel_systems")]
thread_pool: rusty_pool::ThreadPool,
}
impl Default for World{
fn default() -> World {
#[cfg(feature="parallel_systems")]
let (done_tx, done_rx) = crossbeam::channel::unbounded();
World{
storages: Storages::default(),
resources: ResourcesContainer::default(),
next_guid: AtomicUsize::new(0),
systems: Systems::default(),
priority_queue: Vec::new(),
predecessors_cache: PredecessorsCache::default(),
#[cfg(feature="parallel_systems")]
done_tx,
#[cfg(feature="parallel_systems")]
done_rx,
#[cfg(feature="stats_events")]
total_duration: Property::default(),
#[cfg(feature="dynamic_systems")]
dynamic_systems: DynamicSystemsLoader::new().unwrap(),
#[cfg(feature="parallel_systems")]
thread_pool: rusty_pool::ThreadPool::default(),
}
}
}
impl World{
pub fn new() -> World{
World::default()
}
pub fn register_with_capacity<'r, C: ComponentSend>(&mut self, capacity: usize)
where
for<'s> <C as Component>::Storage: Storage<'s, C>,
<<C as Component>::Storage as Storage<'r, C>>::Get: DebugParameter,
{
self.storages_mut().register::<C>(Some(capacity));
}
pub fn register_thread_local_with_capacity<'r, C: ComponentSend>(&mut self, capacity: usize)
where
for<'s> <C as Component>::Storage: Storage<'s, C>,
<<C as Component>::Storage as Storage<'r, C>>::Get: DebugParameter,
{
self.storages_mut().register_thread_local::<C>(Some(capacity));
}
fn storages_mut(&mut self) -> &mut Storages{
&mut self.storages
}
fn storages(&self) -> &Storages{
&self.storages
}
fn resources_container_mut(&mut self) -> &mut ResourcesContainer{
&mut self.resources
}
fn resources_container(&self) -> &ResourcesContainer{
&self.resources
}
pub fn new_entity(&mut self) -> EntityBuilder{
let next_guid = self.next_guid();
EntityBuilder{
components_mask: bitmask::zero(),
guid: next_guid,
storages: self.storages_mut(),
}
}
pub fn component_mask<C: 'static>(&self) -> MaskType{
self.storages().component_mask::<C>()
}
pub fn entities(&mut self) -> Entities{
Entities{
storages: self.storages().substorages_all(),
}
}
pub fn entities_thread_local(&mut self) -> EntitiesThreadLocal{
EntitiesThreadLocal{
storages: self.storages().substorages_all(),
}
}
pub fn entities_creation(&mut self) -> EntitiesCreation{
EntitiesCreation{
storages: self.storages.substorages_all(),
next_guid: &self.next_guid,
}
}
#[cfg(feature="debug_parameters")]
pub fn debug_entities(&mut self) -> EntitiesDebug{
EntitiesDebug{
storages: self.storages.substorages_all()
}
}
pub fn add_component_to<'r, C: ComponentSend>(&mut self, entity: &Entity, component: C)
where
for<'s> <C as Component>::Storage: Storage<'s, C>,
<<C as Component>::Storage as Storage<'r, C>>::Get: DebugParameter,
{
self.storages_mut().add_component_to(entity, component)
}
pub fn add_component_to_thread_local<'r, C: ComponentThreadLocal>(&mut self, entity: &Entity, component: C)
where
for<'s> <C as Component>::Storage: Storage<'s, C>,
<<C as Component>::Storage as Storage<'r, C>>::Get: DebugParameter,
{
self.storages_mut().add_component_to_thread_local(entity, component)
}
pub fn add_tag_to<C: 'static>(&mut self, entity: &Entity){
self.storages_mut().add_tag_to::<C>(entity)
}
pub fn add_child_component_to<'r, C: ComponentSend>(&mut self, parent: &Entity, entity: &Entity, component: C)
where
for<'b> <C as Component>::Storage: HierarchicalStorage<'b,C>,
<<C as Component>::Storage as Storage<'r, C>>::Get: DebugParameter,
{
self.storages_mut().add_child_component_to(parent, entity, component)
}
pub fn add_child_component_to_thread_local<'r, C: ComponentThreadLocal>(&mut self, parent: &Entity, entity: &Entity, component: C)
where
for<'b> <C as Component>::Storage: HierarchicalStorage<'b,C>,
<<C as Component>::Storage as Storage<'r, C>>::Get: DebugParameter,
{
self.storages_mut().add_child_component_to_thread_local(parent, entity, component)
}
pub fn add_slice_component_to<'r, C, I>(&mut self, entity: &Entity, component: I)
where
C: OneToNComponentSend,
for<'s> <C as Component>::Storage: OneToNStorage<'s, C>,
<<C as Component>::Storage as Storage<'r, C>>::Get: DebugParameter,
I: IntoIterator<Item = C>
{
self.storages_mut().add_slice_component_to(entity, component)
}
pub fn add_slice_component_to_thread_local<'r, C, I>(&mut self, entity: &Entity, component: I)
where
C: OneToNComponentThreadLocal,
for<'s> <C as Component>::Storage: OneToNStorage<'s, C>,
<<C as Component>::Storage as Storage<'r, C>>::Get: DebugParameter,
I: IntoIterator<Item = C>
{
self.storages_mut().add_slice_component_to_thread_local(entity, component)
}
pub fn remove_component_from<'r, C: Component>(&mut self, entity: &Entity)
where
for<'s> <C as Component>::Storage: Storage<'s, C>,
<<C as Component>::Storage as Storage<'r, C>>::Get: DebugParameter,
{
self.storages_mut().remove_component_from::<C>(entity)
}
pub fn remove_entity(&mut self, entity: &Entity){
self.storages_mut().remove_entity(entity)
}
pub fn add_resource<T: 'static + Send>(&mut self, resource: T){
self.resources_container_mut().add(resource)
}
pub fn add_resource_as_trait<T, U, F, FMut>(&mut self, resource: (T, F, FMut))
where T: 'static + Send,
U: 'static + Send + ?Sized,
F: Fn(&T) -> &U + 'static,
FMut: Fn(&mut T) -> &mut U + 'static,
{
let (resource, f, fmut) = resource;
self.resources_container_mut().add(resource);
self.resources_container_mut().add_as_trait::<T,U,F,FMut>(f,fmut)
}
pub fn resources(&self) -> Resources{
Resources{
resources: self.resources_container(),
resource_mask_r: None,
resource_mask_w: None,
system_info: "",
#[cfg(feature="dynamic_systems")]
dynamic_systems: &self.dynamic_systems,
}
}
pub fn entities_and_resources(&mut self) -> (Entities, Resources) {
let entities = Entities {
storages: self.storages.substorages_all()
};
let resources = self.resources();
(entities, resources)
}
pub fn remove_resource<T: 'static>(&mut self) -> Option<T> {
self.resources_container_mut().remove::<T>()
}
pub fn add_resource_thread_local<T: 'static>(&mut self, resource: T){
self.resources_container_mut().add_thread_local(resource);
}
pub fn add_resource_as_trait_thread_local<T, U, F, FMut>(&mut self, resource: (T, F, FMut))
where T: 'static,
U: 'static + ?Sized,
F: Fn(&T) -> &U + 'static,
FMut: Fn(&mut T) -> &mut U + 'static,
{
let (resource, f, fmut) = resource;
self.resources_container_mut().add_thread_local(resource);
self.resources_container_mut().add_as_trait_thread_local::<T,U,F,FMut>(f, fmut)
}
pub fn resource<T: 'static>(&self) -> Option<ReadGuardRef<T>>{
self.resources_container().get(None, "")
}
pub fn resource_as<T: 'static + ?Sized>(&self) -> Option<ReadGuardRef<T>>{
self.resources_container().as_trait(None, "")
}
pub fn resource_mut<T: 'static>(&self) -> Option<WriteGuardRef<T>>{
self.resources_container().get_mut(None, "")
}
pub fn resources_thread_local(&self) -> ResourcesThreadLocal{
ResourcesThreadLocal{
resources: self.resources_container(),
resource_mask_r: None,
resource_mask_w: None,
system_info: "",
#[cfg(feature="dynamic_systems")]
dynamic_systems: &self.dynamic_systems,
}
}
pub fn entities_and_resources_thread_local(&mut self) -> (EntitiesThreadLocal, ResourcesThreadLocal) {
let entities = EntitiesThreadLocal {
storages: self.storages.substorages_all()
};
let resources = self.resources_thread_local();
(entities, resources)
}
pub fn resources_creation(&mut self) -> ResourcesCreation{
ResourcesCreation{
resources: &mut self.resources,
system_info: "",
}
}
pub fn entities_and_resources_creation(&mut self) -> (EntitiesCreation, ResourcesCreation) {
let entities = EntitiesCreation {
storages: self.storages.substorages_all(),
next_guid: &self.next_guid,
};
let resources = ResourcesCreation{
resources: &mut self.resources,
system_info: "",
};
(entities, resources)
}
fn storage_registry(&mut self) -> &mut StorageRegistry {
self.storages.registry()
}
pub(crate) fn add_any_system<S, TraitObject>(
&mut self,
system: S,
stat: Option<StatsType>) -> &mut World
where S: AnySystem<TraitObject> + 'static
{
self.priority_queue.clear();
self.systems.add_system(
system,
stat,
None,
None,
None,
None,
None
);
self
}
pub(crate) fn add_any_system_with_checks<S, TraitObject>(&mut self,
system: S,
stat: Option<StatsType>,
checks: SystemConditionElse<TraitObject>) -> &mut World
where S: AnySystem<TraitObject> + 'static,
{
self.priority_queue.clear();
self.systems.add_system(
system,
stat,
Some(checks),
None,
None,
None,
None
);
self
}
pub(crate) fn add_any_send_system<S>(&mut self,
system: S,
stat: Option<StatsType>,
checks: Option<SystemConditionSend>,
needs: Option<Vec<TypeId>>,
updates: Option<Vec<TypeId>>,
reads: Option<Vec<TypeId>>,
writes: Option<Vec<TypeId>>,
) -> &mut World
where S: System + 'static,
{
self.priority_queue.clear();
let checks = checks.or_else(|| S::checks(self.storage_registry()));
let stat = stat.or_else(|| S::name().map(|n| StatsType::Cpu(n) ));
self.systems.add_system(
system,
stat,
checks,
needs,
updates,
reads,
writes,
);
self
}
pub(crate) fn add_any_send_system_once<S>(&mut self,
system: S,
stat: Option<StatsType>,
checks: Option<SystemConditionSendOnce>,
needs: Option<Vec<TypeId>>,
updates: Option<Vec<TypeId>>,
reads: Option<Vec<TypeId>>,
writes: Option<Vec<TypeId>>,
) -> &mut World
where S: SystemOnce + 'static,
{
self.priority_queue.clear();
let checks = checks.or_else(|| S::checks(self.storage_registry()));
let stat = stat.or_else(|| S::name().map(|n| StatsType::Cpu(n) ));
self.systems.add_system(
system,
stat,
checks,
needs,
updates,
reads,
writes,
);
self
}
pub(crate) fn add_any_thread_local_system<S>(&mut self,
system: S,
stat: Option<StatsType>,
checks: Option<SystemConditionThreadLocal>,
needs: Option<Vec<TypeId>>,
updates: Option<Vec<TypeId>>,
reads: Option<Vec<TypeId>>,
writes: Option<Vec<TypeId>>) -> &mut World
where S: SystemThreadLocal + 'static,
{
self.priority_queue.clear();
let checks = checks.or_else(|| S::checks(self.storage_registry()));
let stat = stat.or_else(|| S::name().map(|n| if S::runs_on_gpu() {
StatsType::Gpu(n)
}else{
StatsType::Cpu(n)
}));
self.systems.add_system(
system,
stat,
checks,
needs,
updates,
reads,
writes,
);
self
}
pub(crate) fn add_any_thread_local_system_once<S>(&mut self,
system: S,
stat: Option<StatsType>,
checks: Option<SystemConditionThreadLocalOnce>,
needs: Option<Vec<TypeId>>,
updates: Option<Vec<TypeId>>,
reads: Option<Vec<TypeId>>,
writes: Option<Vec<TypeId>>) -> &mut World
where S: SystemOnceThreadLocal + 'static,
{
self.priority_queue.clear();
let checks = checks.or_else(|| S::checks(self.storage_registry()));
let stat = stat.or_else(|| S::name().map(|n| if S::runs_on_gpu() {
StatsType::Gpu(n)
}else{
StatsType::Cpu(n)
}));
self.systems.add_system(
system,
stat,
checks,
needs,
updates,
reads,
writes,
);
self
}
pub(crate) fn add_any_creation_system<S>(&mut self,
system: S,
stat: Option<StatsType>,
checks: Option<SystemConditionCreation>,
needs: Option<Vec<TypeId>>,
updates: Option<Vec<TypeId>>,
reads: Option<Vec<TypeId>>,
writes: Option<Vec<TypeId>>) -> &mut World
where S: CreationSystem + 'static,
{
self.priority_queue.clear();
let checks = checks.or_else(|| S::checks(self.storage_registry()));
let stat = stat.or_else(|| S::name().map(|n| if S::runs_on_gpu() {
StatsType::Gpu(n)
}else{
StatsType::Cpu(n)
}));
self.systems.add_system(
system,
stat,
checks,
needs,
updates,
reads,
writes,
);
self
}
pub(crate) fn add_any_creation_system_once<S>(&mut self,
system: S,
stat: Option<StatsType>,
checks: Option<SystemConditionCreationOnce>,
needs: Option<Vec<TypeId>>,
updates: Option<Vec<TypeId>>,
reads: Option<Vec<TypeId>>,
writes: Option<Vec<TypeId>>) -> &mut World
where S: CreationSystemOnce + 'static,
{
self.priority_queue.clear();
let checks = checks.or_else(|| S::checks(self.storage_registry()));
let stat = stat.or_else(|| S::name().map(|n| if S::runs_on_gpu() {
StatsType::Gpu(n)
}else{
StatsType::Cpu(n)
}));
self.systems.add_system(
system,
stat,
checks,
needs,
updates,
reads,
writes,
);
self
}
pub fn add_system<S>(&mut self, system: S) -> &mut World
where S: System + 'static
{
if let Some(checks) = S::checks(self.storage_registry()){
self.add_any_system_with_checks(
system,
S::name().map(|name| StatsType::Cpu(name)),
checks)
}else{
self.add_any_system(
system,
S::name().map(|name| StatsType::Cpu(name)))
}
}
pub fn add_system_once<S>(&mut self, system: S) -> &mut World
where S: SystemOnce + 'static
{
if let Some(checks) = S::checks(self.storage_registry()){
self.add_any_system_with_checks(
system,
S::name().map(|name| StatsType::Cpu(name)),
checks)
}else{
self.add_any_system(
system,
S::name().map(|name| StatsType::Cpu(name)))
}
}
pub fn add_system_with_data<S,D>(&mut self, system: S, data: D) -> &mut World
where S: FnMut(&mut D, Entities, Resources) + Send + 'static,
D: Send + 'static
{
self.add_any_system((system, data), None)
}
pub fn add_system_thread_local<S>(&mut self, system: S) -> &mut World
where S: SystemThreadLocal + 'static
{
let name = if S::runs_on_gpu() {
S::name().map(|name| StatsType::Gpu(name))
}else{
S::name().map(|name| StatsType::Cpu(name))
};
if let Some(checks) = S::checks(self.storage_registry()) {
self.add_any_system_with_checks(
system,
name,
checks)
}else{
self.add_any_system(system, name)
}
}
pub fn add_system_once_thread_local<S>(&mut self, system: S) -> &mut World
where S: SystemOnceThreadLocal + 'static
{
let name = if S::runs_on_gpu() {
S::name().map(|name| StatsType::Gpu(name))
}else{
S::name().map(|name| StatsType::Cpu(name))
};
if let Some(checks) = S::checks(self.storage_registry()) {
self.add_any_system_with_checks(
system,
name,
checks)
}else{
self.add_any_system(system, name)
}
}
pub fn add_system_thread_local_with_data<S,D>(&mut self, system: S, data: D) -> &mut World
where S: FnMut(&mut D, EntitiesThreadLocal, ResourcesThreadLocal) + 'static,
D: 'static
{
self.add_any_system((system, data), None)
}
pub fn add_creation_system<S>(&mut self, system: S) -> &mut World
where S: CreationSystem + 'static
{
let name = if S::runs_on_gpu() {
S::name().map(|name| StatsType::Gpu(name))
}else{
S::name().map(|name| StatsType::Cpu(name))
};
if let Some(checks) = S::checks(self.storage_registry()) {
self.add_any_system_with_checks(
system,
name,
checks)
}else{
self.add_any_system(system, name)
}
}
pub fn add_creation_system_once<S>(&mut self, system: S) -> &mut World
where S: CreationSystemOnce + 'static
{
let name = if S::runs_on_gpu() {
S::name().map(|name| StatsType::Gpu(name))
}else{
S::name().map(|name| StatsType::Cpu(name))
};
if let Some(checks) = S::checks(self.storage_registry()) {
self.add_any_system_with_checks(
system,
name,
checks)
}else{
self.add_any_system(system, name)
}
}
#[cfg(feature = "async")]
pub fn add_creation_system_async<S>(&mut self, system: S) -> &mut World
where S: CreationSystemAsync + 'static
{
let name = if S::runs_on_gpu() {
S::name().map(|name| StatsType::Gpu(name))
}else{
S::name().map(|name| StatsType::Cpu(name))
};
self.priority_queue.clear();
let checks = S::checks(self.creation_proxy());
let creation_proxy = self.creation_proxy();
let future = system.run(creation_proxy);
self.systems.add_creation_system_async::<S>(future, name, checks);
self
}
pub fn add_creation_system_with_data<S, D>(&mut self, system: S, data: D) -> &mut World
where S: FnMut(&mut D, EntitiesCreation, ResourcesCreation) + 'static,
D: 'static
{
self.add_any_system((system, data), None)
}
pub fn add_system_with<S>(&mut self, system: S) -> systems::Builder<S>
where S: System + 'static
{
systems::Builder::new(system, self)
}
pub fn add_system_once_with<S>(&mut self, system: S) -> systems::BuilderOnce<S>
where S: SystemOnce + 'static
{
systems::BuilderOnce::new(system, self)
}
pub fn add_system_thread_local_with<S>(&mut self, system: S) -> systems::BuilderThreadLocal<S>
where S: SystemThreadLocal + 'static
{
systems::BuilderThreadLocal::new(system, self)
}
pub fn add_system_once_thread_local_with<S>(&mut self, system: S) -> systems::BuilderOnceThreadLocal<S>
where S: SystemOnceThreadLocal + 'static
{
systems::BuilderOnceThreadLocal::new(system, self)
}
pub fn add_creation_system_with<S>(&mut self, system: S) -> systems::BuilderCreation<S>
where S: CreationSystem + 'static
{
systems::BuilderCreation::new(system, self)
}
pub fn add_creation_system_once_with<S>(&mut self, system: S) -> systems::BuilderCreationOnce<S>
where S: CreationSystemOnce + 'static
{
systems::BuilderCreationOnce::new(system, self)
}
#[cfg(feature = "debug_parameters")]
pub fn add_debug_system<S>(&mut self, system: S) -> &mut World
where S: SystemDebug + 'static
{
self.add_any_system(system, None)
}
#[cfg(feature="dynamic_systems")]
pub fn preload_dynamic_libraries(&mut self, libs: &[&str]) -> Result<(), String> {
self.dynamic_systems.preload_libraries(libs)
}
#[cfg(feature="dynamic_systems")]
pub fn new_dynamic_system(&mut self, system_path: &str) -> &mut World{
let system = self.dynamic_systems.new_system(system_path).unwrap();
self.add_any_system(system, None)
}
#[cfg(feature="dynamic_systems")]
pub fn new_dynamic_system_with(&mut self, system_path: &str) -> systems::Builder<DynamicFunction<for<'r, 's> fn(Entities<'r>, Resources<'s>)>>{
let system = self.dynamic_systems.new_system(system_path).unwrap();
systems::Builder::new(system, self)
}
#[cfg(feature="dynamic_systems")]
pub fn new_dynamic_system_with_data<D: Send + 'static>(&mut self, system_path: &str, data: D) -> &mut World{
let system = self.dynamic_systems.new_system_with_data(system_path).unwrap();
self.add_any_system((system, data), None)
}
#[cfg(feature="dynamic_systems")]
pub fn new_dynamic_system_with_data_with<D: Send + 'static>(&mut self, system_path: &str, data: D) -> systems::Builder<(DynamicFunction<for<'r, 's> fn(*mut std::ffi::c_void, Entities<'r>, Resources<'s>)>, D)>{
let system = self.dynamic_systems.new_system_with_data(system_path).unwrap();
systems::Builder::new((system, data), self)
}
#[cfg(feature="dynamic_systems")]
pub fn new_dynamic_system_thread_local(&mut self, system_path: &str) -> &mut World{
let system = self.dynamic_systems.new_system_thread_local(system_path).unwrap();
self.add_any_system(system, None)
}
#[cfg(feature="dynamic_systems")]
pub fn new_dynamic_system_thread_local_with(&mut self, system_path: &str) -> systems::BuilderThreadLocal<DynamicFunction<for<'r, 's> fn(EntitiesThreadLocal<'r>, ResourcesThreadLocal<'s>)>>{
let system = self.dynamic_systems.new_system_thread_local(system_path).unwrap();
systems::BuilderThreadLocal::new(system, self)
}
#[cfg(feature="dynamic_systems")]
pub fn new_dynamic_system_thread_local_with_data<D: 'static>(&mut self, system_path: &str, data: D) -> &mut World{
let system = self.dynamic_systems.new_system_thread_local_with_data(system_path).unwrap();
self.add_any_system((system, data), None)
}
#[cfg(feature="dynamic_systems")]
pub fn new_dynamic_system_thread_local_with_data_with<D: 'static>(&mut self, system_path: &str, data: D) -> systems::BuilderThreadLocal<(DynamicFunction<for<'r, 's> fn(*mut std::ffi::c_void, EntitiesThreadLocal<'r>, ResourcesThreadLocal<'s>)>, D)>{
let system = self.dynamic_systems.new_system_thread_local_with_data(system_path).unwrap();
systems::BuilderThreadLocal::new((system, data), self)
}
#[cfg(feature="dynamic_systems")]
pub fn new_dynamic_creation_system(&mut self, system_path: &str) -> &mut World{
let system = self.dynamic_systems.new_creation_system(system_path).unwrap();
self.add_any_system(system, None)
}
#[cfg(feature="dynamic_systems")]
pub fn new_dynamic_creation_system_with_data<D: 'static>(&mut self, system_path: &str, data: D) -> &mut World{
let system = self.dynamic_systems.new_creation_system_with_data(system_path).unwrap();
self.add_any_system((system, data), None)
}
#[cfg(feature="dynamic_systems")]
pub fn run_dynamic_system_once(&mut self, system_path: &str) -> &mut World{
let mut system = self.dynamic_systems.new_system(system_path).unwrap();
system.run(self.entities(), self.resources());
self
}
#[cfg(feature="dynamic_systems")]
pub fn run_dynamic_system_once_thread_local(&mut self, system_path: &str) -> &mut World{
let mut system = self.dynamic_systems.new_system_thread_local(system_path).unwrap();
system.run(self.entities_thread_local(), self.resources_thread_local());
self
}
#[cfg(feature="dynamic_systems")]
pub fn new_dynamic_system_with_name(&mut self, system_path: &str, name: &str) -> &mut World{
let system = self.dynamic_systems.new_system(system_path).unwrap();
self.add_any_system(system, Some(StatsType::Cpu(name)))
}
#[cfg(feature="dynamic_systems")]
pub fn new_dynamic_system_with_name_thread_local(&mut self, system_path: &str, name: &str) -> &mut World{
let system = self.dynamic_systems.new_system_thread_local(system_path).unwrap();
self.add_any_system(system, Some(StatsType::Cpu(name)))
}
#[cfg(feature="dynamic_systems")]
pub unsafe fn get_dynamic_symbol<S>(&self, symbol_path: &str) -> Result<DynamicSymbol<S>, String>{
self.dynamic_systems.get_dynamic_symbol(symbol_path)
}
#[cfg(feature="dynamic_systems")]
pub fn add_dynamic_symbol_watch(&mut self, system_path: &str) -> Result<(), String>{
self.dynamic_systems.add_watch(system_path)
}
pub fn add_barrier<B: systems::Barrier + 'static>(&mut self) -> &mut World
{
self.systems.add_barrier::<B>();
self
}
#[cfg(feature="stats_events")]
pub fn stats(&mut self) -> impl Iterator<Item = (&str, Property<'static, crate::Stat>)>{
self.systems.stats()
}
#[cfg(all(feature="stats_events", feature="glin"))]
pub fn gpu_stats<C: glin::CreationContext>(&mut self, gl: &C) -> impl Iterator<Item = (&str, Property<'static, Duration>)>{
self.systems.gpu_stats(gl)
}
#[cfg(feature="stats_events")]
pub fn enabled_systems(&mut self) -> impl Iterator<Item = (&str, Property<'static, bool>)>{
self.systems.enabled_systems()
}
#[cfg(feature="stats_events")]
pub fn export_tracing_stats<P: AsRef<Path>>(&self, path: P){
self.systems.export_tracing_stats(path)
}
#[cfg(feature="dynamic_systems")]
pub fn start_dynamic_systems_watch(&mut self) -> Result<(), String>{
self.dynamic_systems.start()
}
pub fn render_systems_dependency_graph<P: AsRef<Path>>(&mut self, file: P){
self.systems.render_dependency_graph(file)
}
pub fn run_once(&mut self){
#[cfg(not(feature="parallel_systems"))]
self.run_single_threaded();
#[cfg(feature="parallel_systems")]
self.run_multi_threaded();
}
#[cfg(feature="parallel_systems")]
pub fn run_multi_threaded(&mut self) {
#[cfg(feature="stats_events")]
let then = time::now();
if self.priority_queue.is_empty() || self.resources.take_traits_changed() {
let reverse_trait_index = self.resources.reverse_trait_index();
self.priority_queue = self.systems.topological_sort(reverse_trait_index)
.map_err(|err| format!("Error solving dependency graph, found a cycle: {:?}", err.join(" -> ")))
.unwrap();
self.predecessors_cache = self.systems.predecessors_cache(reverse_trait_index);
let resources_index = self.predecessors_cache.take_resources_index();
self.storages.set_resources_index(resources_index.clone());
self.resources.set_resources_index(resources_index);
}
#[cfg(feature="stats_events")]
self.systems.reset_stats();
let (send_systems, mut _stats): (systems::SendSystems, systems::SendSystemsStats) = unsafe{
mem::transmute(self.systems.send_systems())
};
let mut needs_recalculate_priorities = false;
struct DoneGuard{
sender: crossbeam::channel::Sender<Result<SystemHandle, SystemHandle>>,
system: Result<SystemHandle, SystemHandle>,
}
impl Drop for DoneGuard{
fn drop(&mut self) {
self.sender.send(self.system).unwrap()
}
}
while !self.predecessors_cache.all_done() {
let mut systems = self.predecessors_cache.iter().collect::<Vec<_>>();
systems.sort_unstable_by_key(|(priority, _)| match priority {
Priority::Send(_) | Priority::SendOnce(_) => 0,
_ => 1,
});
for (priority, system) in systems {
if let Priority::Send(priority) = priority {
let mut done_tx = DoneGuard{
sender: self.done_tx.clone(),
system: Err(system),
};
let storages = unsafe{ delete_lifetime(&self.storages) };
let resources = unsafe{ delete_lifetime(&self.resources) };
let send_systems = send_systems.clone();
if let Some(system_wrapper) = send_systems.send_system(priority, storages, resources) {
self.thread_pool.execute(move ||{
let mut done_tx = done_tx;
system_wrapper.run();
done_tx.system = Ok(done_tx.system.unwrap_err());
});
}else{
done_tx.system = Ok(done_tx.system.unwrap_err());
}
}else if let Priority::SendOnce(priority) = priority {
let mut done_tx = DoneGuard{
sender: self.done_tx.clone(),
system: Err(system),
};
let storages = unsafe{ delete_lifetime(&self.storages) };
let resources = unsafe{ delete_lifetime(&self.resources) };
let send_systems = send_systems.clone();
if let Some(system_wrapper) = send_systems.send_once_system(priority, storages, resources) {
self.thread_pool.execute(move ||{
let mut done_tx = done_tx;
system_wrapper.run();
done_tx.system = Ok(done_tx.system.unwrap_err());
});
}else{
done_tx.system = Ok(done_tx.system.unwrap_err());
}
}else{
needs_recalculate_priorities |= self.systems.run_one(
priority,
&self.storages,
&mut self.resources,
&self.next_guid,
#[cfg(feature="dynamic_systems")]
&self.dynamic_systems);
self.done_tx.send(Ok(system)).unwrap();
}
}
if let Ok(system) = self.done_rx.recv(){
match system {
Ok(system) => self.predecessors_cache.done(system),
Err(system) => {
let priority = self.predecessors_cache.system_priority(system);
panic!("Error running system \"{}\" at {}", self.systems.system_name(priority), self.systems.system_file_line_info(priority));
}
}
}
for system in self.done_rx.try_iter() {
match system {
Ok(system) => self.predecessors_cache.done(system),
Err(system) => {
let priority = self.predecessors_cache.system_priority(system);
panic!("Error running system \"{}\"", self.systems.system_name(priority));
}
}
}
}
while self.predecessors_cache.systems_running() > 0 {
if let Ok(system) = self.done_rx.recv() {
match system {
Ok(system) => self.predecessors_cache.done(system),
Err(system) => {
let priority = self.predecessors_cache.system_priority(system);
panic!("Error running system \"{}\"", self.systems.system_name(priority));
}
}
}
}
#[cfg(feature="stats_events")]
_stats.receive();
self.storages_mut().update();
#[cfg(feature="stats_events")]
self.systems.send_stats();
self.predecessors_cache.reset();
if needs_recalculate_priorities {
self.priority_queue.clear()
}
#[cfg(feature="stats_events")]
{
let now = time::now();
let stat = Stat::new(then, now, thread_id());
self.total_duration.set(stat);
}
}
pub fn run_single_threaded(&mut self){
#[cfg(feature="stats_events")]
let then = time::now();
if self.priority_queue.is_empty() || self.resources.take_traits_changed(){
let reverse_trait_index = self.resources.reverse_trait_index();
self.priority_queue = self.systems.topological_sort(reverse_trait_index)
.map_err(|err| format!("Error solving dependency graph, found a cycle: {:?}", err.join(" -> ")))
.unwrap();
self.predecessors_cache = self.systems.predecessors_cache(reverse_trait_index);
let resources_index = self.predecessors_cache.take_resources_index();
self.storages.set_resources_index(resources_index.clone());
self.resources.set_resources_index(resources_index);
}
#[cfg(feature="stats_events")]
self.systems.reset_stats();
let mut needs_recalculate_priorities = false;
for (system, _operator_id) in self.priority_queue.iter(){
needs_recalculate_priorities |= self.systems.run_one(
*system,
&self.storages,
&mut self.resources,
&self.next_guid,
#[cfg(feature="dynamic_systems")]
&self.dynamic_systems);
}
self.storages_mut().update();
#[cfg(feature="stats_events")]
self.systems.send_stats();
if needs_recalculate_priorities {
self.priority_queue.clear();
}
#[cfg(feature="stats_events")]
{
let now = time::now();
let stat = Stat::new(then, now, thread_id());
self.total_duration.set(stat);
}
}
#[cfg(feature="stats_events")]
pub fn total_duration_stats(&self) -> &Property<'static, Stat>{
&self.total_duration
}
pub(crate) fn next_guid(&mut self) -> usize{
self.next_guid.fetch_add(1, Ordering::SeqCst)
}
pub fn is_registered<C: Component>(&self) -> bool{
self.storages().is_registered::<C>()
}
pub fn creation_storage<C: Component>(&mut self) -> CreationSto<C> {
self.storages_mut().creation_storage::<C>()
}
pub fn component_for<C: Component>(&self, entity: &Entity) -> Option<Ptr<C>>
where for<'s> <C as Component>::Storage: Storage<'s, C>
{
if let Some(storage) = self.storage::<C>() {
if storage.contains(entity.guid()) {
Some(Ptr::new(storage, *entity))
}else{
None
}
}else{
None
}
}
pub fn component_for_mut<C: Component>(&self, entity: &Entity) -> Option<PtrMut<C>>
where for<'s> <C as Component>::Storage: Storage<'s, C>
{
if let Some(storage) = self.storage_mut::<C>() {
if storage.contains(entity.guid()) {
Some(PtrMut::new(storage, *entity))
}else{
None
}
}else{
None
}
}
pub fn storage_for<'r, S>(&'r self) -> Sto<'r, S>
where S: UnorderedData<'r> + ReadOnlyOp<'r>
{
Sto::new(
S::storage(self),
Entities{
storages: self.storages.substorages_all()
}
)
}
pub fn storage_for_mut<'r, S>(&'r mut self) -> Sto<'r, S>
where S: UnorderedData<'r>
{
Sto::new(
S::storage(self),
Entities{
storages: self.storages.substorages_all(),
}
)
}
}
impl EntitiesStorage for World {
fn storage<C: Component>(&self) -> Option<ReadGuardRef<<C as Component>::Storage>> {
let storages = &self.storages as *const Storages;
unsafe{ (*storages).storage_thread_local::<C>() }
}
fn storage_mut<C: Component>(&self) -> Option<StorageWriteGuard<C>> {
let storages = &self.storages as *const Storages;
unsafe{ (*storages).storage_thread_local_mut::<C>() }
}
fn entities_ref(&self) -> &[(Entity, MaskType)]{
let storages = &self.storages as *const Storages;
unsafe{ (*storages).entities_ref() }
}
fn component_mask<C: 'static>(&self) -> MaskType{
self.storages.component_mask::<C>()
}
fn entities_for_mask<S: FastIndexExt>(&self, query_mask: Bitmask, storage: &S) -> IndexGuard {
let storages = &self.storages as *const Storages;
unsafe{ (*storages).entities_for_mask(query_mask, storage) }
}
fn lazy_entities_for_mask(&self, query_mask: Bitmask) -> LazyIndexGuard {
LazyIndexGuard{
query_mask,
storages: self.storages().substorages_all(),
index_guard: UnsafeCell::new(None),
}
}
fn ordered_entities_for<C: Component, S: FastIndexExt>(&self, query_mask: Bitmask, unordered_storage: &S) -> OrderedIndexGuard
where for<'b> <C as Component>::Storage: HierarchicalStorage<'b,C>
{
let storages = &self.storages as *const Storages;
unsafe{ (*storages).ordered_entities_for_thread_local::<C,S>(query_mask, unordered_storage) }
}
}
impl<'a> EntitiesExt<'a> for World {
fn iter_for<'e, S: UnorderedDataSend<'e> + ReadOnlyOp<'e>>(&'e self) -> <S as UnorderedData<'e>>::Iter {
S::into_iter(self)
}
fn iter_for_mut<'e, S: UnorderedDataSend<'e>>(&'e mut self) -> <S as UnorderedData<'e>>::IterMut {
S::into_iter_mut(self)
}
fn ordered_iter_for<'e, S: OrderedDataSend<'e> + ReadOnlyOrderedOp<'e>>(&'e self) -> <S as OrderedData<'e>>::Iter{
S::into_iter(self)
}
fn ordered_iter_for_mut<'e, S: OrderedDataSend<'e>>(&'e mut self) -> <S as OrderedData<'e>>::Iter{
S::into_iter(self)
}
fn iter_for_entities<'e, U, E>(&'e self, entities: E) -> E::IntoEntitiesIter
where
E: IntoEntitiesIterator<'e, U::Storage>,
U: UnorderedDataSend<'e>,
U::Storage: ReadOnlyStorage
{
entities.storage_entities_iter(U::storage(self))
}
fn iter_for_entities_mut<'e, U, E>(&'e mut self, entities: E) -> E::IntoEntitiesIterMut
where
E: IntoEntitiesIterator<'e, U::Storage>,
U: UnorderedDataSend<'e>,
{
entities.storage_entities_iter_mut(U::storage(self))
}
fn iter_for_entities_opt<'e, U, E>(&'e self, entities: E) -> E::IntoEntitiesOptIter
where
E: IntoEntitiesIterator<'e, U::Storage>,
U: UnorderedDataSend<'e>,
U::Storage: ReadOnlyStorage
{
entities.storage_entities_opt_iter(U::storage(self))
}
fn iter_for_entities_opt_mut<'e, U, E>(&'e mut self, entities: E) -> E::IntoEntitiesOptIterMut
where
E: IntoEntitiesIterator<'e, U::Storage>,
U: UnorderedDataSend<'e>,
{
entities.storage_entities_opt_iter_mut(U::storage(self))
}
fn entity_components<'r, S>(&'r self, entity: &Entity) -> Option<<S as UnorderedData<'r>>::ComponentsRef>
where
S: UnorderedDataSend<'r> + ReadOnlyOp<'r> + 'r,
S::Storage: StorageRef<'r, Component = S::ComponentsRef>
{
let mut storage = S::storage(self)?;
if storage.contains(entity.guid()){
let storage = &mut storage as *mut S::Storage;
unsafe{ Some((*storage).get_unchecked(entity.guid())) }
}else{
None
}
}
fn entity_components_mut<'r, S>(&'r mut self, entity: &Entity) -> Option<<S as UnorderedData<'r>>::ComponentsRef>
where
S: UnorderedDataSend<'r> + 'r,
S::Storage: StorageRef<'r, Component = S::ComponentsRef>
{
let mut storage = S::storage(self)?;
if storage.contains(entity.guid()){
let storage = &mut storage as *mut S::Storage;
unsafe{ Some((*storage).get_unchecked(entity.guid())) }
}else{
None
}
}
fn component_for<C: ComponentSend>(&self, entity: &Entity) -> Option<Ptr<C>>
where for<'s> <C as Component>::Storage: Storage<'s, C>
{
if let Some(storage) = self.storage::<C>() {
if storage.contains(entity.guid()) {
Some(Ptr::new(storage, *entity))
}else{
None
}
}else{
None
}
}
fn component_for_mut<C: ComponentSend>(&self, entity: &Entity) -> Option<PtrMut<C>>
where for<'s> <C as Component>::Storage: Storage<'s, C>
{
if let Some(storage) = self.storage_mut::<C>() {
if storage.contains(entity.guid()) {
Some(PtrMut::new(storage, *entity))
}else{
None
}
}else{
None
}
}
fn has_component<C: 'static>(&self, entity: &Entity) -> bool{
self.entities_ref()[entity.guid()].1.clone() & self.component_mask::<C>() != MaskType::zero()
}
fn tree_node_for<C: ComponentSend>(&self, entity: &Entity) -> Option<NodePtr<C>>
where for<'b> <C as Component>::Storage: HierarchicalStorage<'b, C>
{
if let Some(storage) = self.storage::<C>() {
if storage.contains(entity.guid()) {
Some(NodePtr::new(storage, *entity))
}else{
None
}
}else{
None
}
}
fn tree_node_for_mut<C: ComponentSend>(&self, entity: &Entity) -> Option<NodePtrMut<C>>
where for<'b> <C as Component>::Storage: HierarchicalStorage<'b, C>
{
if let Some(storage) = self.storage_mut::<C>() {
if storage.contains(entity.guid()) {
Some(NodePtrMut::new(storage, *entity))
}else{
None
}
}else{
None
}
}
fn changed_iter_for<'r, S>(&'r self) -> EntitiesComponentIter<'r, S::ChangedIter, <S as UnorderedData<'r>>::Storage>
where
S: ChangedDataSend<'r> + EntitiesData + ReadOnlyOp<'r> + 'r,
<S as UnorderedData<'r>>::Storage: StorageRef<'r>
{
let iter = S::changed_iter(self);
S::into_entities_iter(self, iter)
}
fn changed_iter_for_mut<'r, S>(&'r mut self) -> EntitiesComponentIter<'r, S::ChangedIter, <S as UnorderedData<'r>>::Storage>
where
S: ChangedDataSend<'r> + EntitiesData + 'r,
<S as UnorderedData<'r>>::Storage: StorageRef<'r>
{
let iter = S::changed_iter(self);
S::into_entities_iter(self, iter)
}
fn storage_for<'r, S>(&'r self) -> Sto<'r, S>
where S: UnorderedDataSend<'r> + ReadOnlyOp<'r>
{
Sto::new(
S::storage(self),
Entities{
storages: self.storages.substorages_all()
}
)
}
fn storage_for_mut<'r, S>(&'r mut self) -> Sto<'r, S>
where S: UnorderedDataSend<'r>
{
Sto::new(
S::storage(self),
Entities{
storages: self.storages.substorages_all()
}
)
}
}
impl<'a> CreationContextExt<'a> for World {
fn with_entities_and_resources_creation<'e, F, R>(&'e mut self, f: F) -> R
where F: FnOnce(EntitiesCreation<'e>, ResourcesCreation<'e>) -> R
{
let entities = EntitiesCreation{
storages: self.storages.substorages_all(),
next_guid: &self.next_guid,
};
let resources = ResourcesCreation{
resources: &mut self.resources,
system_info: "",
};
f(entities, resources)
}
}
impl ResourcesExt for World {
fn resource<T: 'static + Send>(&self) -> Option<ReadGuardRef<T>> {
self.resources.get(None, "")
}
fn resource_mut<T: 'static + Send>(&self) -> Option<WriteGuardRef<T>> {
self.resources.get_mut(None, "")
}
fn resource_as_trait<T: 'static + Send + ?Sized>(&self) -> Option<ReadGuardRef<T>> {
self.resources.as_trait(None, "")
}
fn resource_as_trait_mut<T: 'static + Send + ?Sized>(&self) -> Option<WriteGuardRef<T>> {
self.resources.as_trait_mut(None, "")
}
}
impl ResourcesThreadLocalExt for World {
fn resource_thread_local<T: 'static>(&self) -> Option<ReadGuardRef<T>> {
self.resources.get(None, "")
}
fn resource_thread_local_mut<T: 'static>(&self) -> Option<WriteGuardRef<T>> {
self.resources.get_mut(None, "")
}
fn resource_as_trait_thread_local<T: 'static + ?Sized>(&self) -> Option<ReadGuardRef<T>> {
self.resources.as_trait(None, "")
}
fn resource_as_trait_thread_local_mut<T: 'static + ?Sized>(&self) -> Option<WriteGuardRef<T>> {
self.resources.as_trait_mut(None, "")
}
}