181 class World :
public std::enable_shared_from_this<World> {
187 pos_t numEntities = 0;
190 class InstantaneousAudioSourceFreeList {
191 entity_t nextID = {INVALID_ENTITY - 1};
196 if (freeList.try_dequeue(
id)) {
206 freeList.enqueue(
id);
208 } instantaneousAudioSourceFreeList;
211 friend class Registry;
221 using const_iterator =
typename decltype(dense_set)::const_iterator_type;
223 template<
typename ... A>
224 inline T& Emplace(entity_id_t
local_id, A&& ... args){
225 auto& ret = dense_set.emplace(std::forward<A>(args)...);
235 inline void Destroy(entity_id_t
local_id){
243 dense_set.erase(dense_set.begin() + sparse_set[
local_id]);
244 aux_set.erase(aux_set.begin() + sparse_set[
local_id]);
246 if (sparse_set[
local_id] < aux_set.size()) {
248 auto owner = aux_set[sparse_set[
local_id]];
249 sparse_set[owner] = sparse_set[
local_id];
252 sparse_set[
local_id] = INVALID_INDEX;
257 return dense_set[sparse_set[
local_id]];
264 inline T& GetFirst(){
265 assert(!dense_set.empty());
269 inline bool HasComponent(entity_id_t
local_id)
const{
270 return local_id < sparse_set.size() && sparse_set[
local_id] != INVALID_ENTITY;
274 return dense_set.begin();
278 return dense_set.end();
282 return dense_set.begin();
286 return dense_set.end();
290 T& Get(entity_id_t idx){
291 return dense_set[idx];
294 auto GetOwner(entity_id_t idx)
const{
298 auto DenseSize()
const{
299 return dense_set.size();
302 auto GetDenseData()
const{
303 return dense_set.data();
306 inline const decltype(dense_set)& GetDense()
const{
313 std::array<char, buf_size> buffer;
314 Function<void(AnySparseSet*,
entity_t,
World*)> _impl_destroyFn;
315 Function<void(AnySparseSet*)> _impl_deallocFn;
319 _impl_destroyFn(
this,
id, world);
322 _impl_deallocFn(
this);
326 inline EntitySparseSet<T>* GetSet() {
327 return reinterpret_cast<EntitySparseSet<T>*
>(buffer.data());
332 AnySparseSet(T* discard) :
333 _impl_destroyFn([](AnySparseSet* thisptr,
entity_t local_id, World* wptr){
334 auto ptr = thisptr->GetSet<T>();
335 if (ptr->HasComponent(local_id.id)){
336 wptr->DestroyComponent<T>(local_id);
339 _impl_deallocFn([](AnySparseSet* thisptr) {
340 thisptr->GetSet<T>()->~EntitySparseSet<T>();
343 static_assert(
sizeof(EntitySparseSet<T>) <= buf_size);
344 new (buffer.data()) EntitySparseSet<T>();
352 locked_node_hashmap<RavEngine::ctti_t, AnySparseSet,SpinLock> componentMap;
355 friend class StaticMesh;
356 friend class SkinnedMeshComponent;
357 friend class RenderEngine;
359 struct MDICommandBase {
360 RGLBufferPtr indirectBuffer, cullingBuffer, indirectStagingBuffer, cuboBuffer, cuboStagingBuffer;
364 struct MDIICommand :
public MDICommandBase {
368 set_t entities{
"Static Mesh Private Entities Buffer"};
369 command(
decltype(mesh) mesh, set_t::index_type index,
const set_t::value_type&
first_value) : mesh(mesh) {
376 struct MDIICommandSkinned :
public MDICommandBase {
381 set_t entities{
"SKinned Mesh Private Entities Buffer"};
382 command(
decltype(mesh) mesh,
decltype(skeleton) skeleton, set_t::index_type index,
const set_t::value_type&
first_value) : mesh(mesh), skeleton(skeleton) {
389 struct DirLightUploadData {
394 int shadowmapBindlessIndex[MAX_CASCADES]{0};
395 float cascadeDistances[MAX_CASCADES]{0};
396 renderlayer_t shadowLayers;
397 renderlayer_t illuminationLayers;
398 uint32_t numCascades;
401 struct DirLightUploadDataPassVarying{
405 struct DirLightUploadDataPassVaryingHostOnly{
410 struct AmbientLightUploadData{
413 renderlayer_t illuminationLayers;
414 uint32_t skyboxBindlessIndex = std::numeric_limits<uint32_t>::max();
415 uint32_t skyboxIrradianceBindlessIndex = std::numeric_limits<uint32_t>::max();
418 struct PointLightUploadData {
425 renderlayer_t shadowLayers;
426 renderlayer_t illuminationLayers;
427 int shadowmapBindlessIndices[6]{ 0 };
430 struct SpotLightDataUpload {
439 renderlayer_t shadowLayers;
440 renderlayer_t illuminationLayers;
446 BufferedVRAMSparseSet<entity_id_t, DirLightUploadData> directionalLightData{
"Directional Light Uniform Private Buffer"};
448 BufferedVRAMSparseSet<entity_id_t, AmbientLightUploadData> ambientLightData{
"Ambient Light Private Buffer"};
450 BufferedVRAMSparseSet<entity_id_t, PointLightUploadData> pointLightData{
"Point Light Private Buffer"};
452 BufferedVRAMSparseSet<entity_id_t, SpotLightDataUpload> spotLightData{
"Point Light Private Buffer"};
454 BufferedVRAMVector<DirLightUploadDataPassVarying> directionalLightPassVarying{
"Directional Light Pass Varying Buffer"};
456 Vector<DirLightUploadDataPassVaryingHostOnly> directionalLightPassVaryingHostOnly;
459 BufferedVRAMVector<renderlayer_t> renderLayers{32};
461 BufferedVRAMVector<perobject_t> perObjectAttributes{ 32 };
465 BufferedVRAMVector<matrix4> worldTransforms{
"World Transform Private Buffer"};
468 OrderedMap<MaterialSort, MDIICommand> staticMeshRenderData;
469 OrderedMap<MaterialSort, MDIICommandSkinned> skinnedMeshRenderData;
471 RGLBufferPtr cuboBuffer;
473 SharedBufferPool stagingBufferPool;
476 RenderData renderData;
478 void updateStaticMeshMaterial(
entity_t localId, Ref<MaterialInstance> oldMat, Ref<MaterialInstance> newMat, Ref<MeshCollectionStatic> mesh);
479 void updateSkinnedMeshMaterial(
entity_t localId, Ref<MaterialInstance> oldMat, Ref<MaterialInstance> newMat, Ref<MeshCollectionSkinned> mesh, Ref<SkeletonAsset> skeleton);
480 void StaticMeshChangedVisibility(
const StaticMesh*);
481 void SkinnedMeshChangedVisibility(
const SkinnedMeshComponent*);
489 return versions.at(
id);
514 return static_cast<T*
>(getfn(
local_id));
517 inline bool operator==(
const elt& other)
const{
518 return full_id == other.full_id;
523 World* world =
nullptr;
527 T* discard =
nullptr;
528 assert(std::find(elts.begin(),elts.end(),elt(world,discard)) ==elts.end());
529 elts.emplace(world,discard);
534 T* discard =
nullptr;
536 auto it = std::find(elts.begin(),elts.end(),
value_erase);
541 inline bool empty()
const{
545 PolymorphicIndirection(
entity_t owner, World* world) : owner(owner), world(world){}
551 template<
typename T,
typename func_t>
554 auto ptr = e.Get<T>(owner);
560 inline auto GetAll() {
564 template<
typename BaseIncludingArgument>
565 inline auto HandleFor(
int idx){
566 auto& elt = elts.at(idx);
567 return BaseIncludingArgument({owner,world},elt.full_id);
584 int nCreatedThisTick = 0;
585 class SparseSetForPolymorphic{
586 using U = PolymorphicIndirection;
587 unordered_vector<U> dense_set;
588 Vector<entity_id_t> sparse_set{INVALID_ENTITY};
592 using const_iterator =
typename decltype(dense_set)::const_iterator_type;
595 inline void Emplace(
entity_t local_id_in, World* world){
596 auto local_id = local_id_in.id;
598 if (!HasForEntity(local_id)){
599 dense_set.emplace(local_id_in,world);
600 if (local_id >= sparse_set.size()){
601 sparse_set.resize(closest_multiple_of<entity_id_t>(local_id+1,2),INVALID_ENTITY);
603 sparse_set[local_id] =
static_cast<decltype(sparse_set)::value_type
>(dense_set.size()-1);
607 GetForEntity(local_id).push<T>();
611 inline void Destroy(entity_id_t local_id){
613 assert(HasForEntity(local_id));
614 GetForEntity(local_id).erase<T>();
617 if (GetForEntity(local_id).empty()){
618 auto denseidx = sparse_set[local_id];
619 dense_set.erase(dense_set.begin() + denseidx);
621 if (denseidx < dense_set.size()) {
622 auto ownerOfMoved = dense_set[denseidx].owner;
623 sparse_set[ownerOfMoved.id] = denseidx;
625 sparse_set[local_id] = INVALID_INDEX;
629 inline U& GetForEntity(entity_id_t local_id){
630 assert(HasForEntity(local_id));
631 return dense_set[sparse_set[local_id]];
634 inline auto SparseToDense(entity_id_t local_id){
635 return sparse_set[local_id];
638 inline auto GetOwnerForDenseIdx(entity_id_t dense_idx) {
639 assert(dense_idx < dense_set.size());
641 return dense_set[dense_idx].owner;
645 inline bool HasForEntity(entity_id_t local_id)
const{
646 return local_id < sparse_set.size() && sparse_set[local_id] != INVALID_ENTITY;
650 return dense_set.begin();
654 return dense_set.end();
658 return dense_set.begin();
662 return dense_set.end();
666 U& Get(entity_id_t idx){
667 return dense_set[idx];
670 auto DenseSize()
const{
671 return dense_set.size();
674 auto GetDenseData()
const{
675 return dense_set.data();
678 inline const decltype(dense_set)& GetDense()
const{
683 UnorderedNodeMap<ctti_t,SparseSetForPolymorphic> polymorphicQueryMap;
685 inline void DestroyEntity(
entity_t local_id){
689 NetworkingDestroy(local_id);
690 for(
auto& pair : componentMap){
691 pair.second.destroyFn(local_id,
this);
694 available.push(local_id.id);
695 versions[local_id.id]++;
699 inline EntitySparseSet<T>* MakeIfNotExists(){
700 return (*componentMap.try_emplace(
RavEngine::CTTI<T>(),
static_cast<T*
>(
nullptr)).first).second.template GetSet<T>();
706 operator Entity()
const;
709 template<
typename T,
typename ... A>
710 inline T& EmplaceComponent(
entity_t local_id, A&& ... args){
711 auto ptr = MakeIfNotExists<T>();
715 if constexpr (HasQueryTypes<T>::value){
717 const auto ids = T::GetQueryTypes();
718 for(
const auto id : ids){
719 polymorphicQueryMap[id].template Emplace<T>(local_id,
this);
724 if constexpr (std::is_same_v<T, DirectionalLight>){
725 renderData.directionalLightData.Emplace(local_id.id);
727 else if constexpr (std::is_same_v<T, AmbientLight>){
728 renderData.ambientLightData.Emplace(local_id.id);
730 else if constexpr (std::is_same_v<T, PointLight>){
731 renderData.pointLightData.Emplace(local_id.id);
733 else if constexpr (std::is_same_v<T, SpotLight>){
734 renderData.spotLightData.Emplace(local_id.id);
738 if constexpr(std::is_constructible<T,Entity, A...>::value || (
sizeof ... (A) == 0 && std::is_constructible<T,Entity>::value)){
739 return ptr->Emplace(local_id.id, EntityRedir{
this,local_id}, std::forward<A>(args)...);
742 return ptr->Emplace(local_id.id,std::forward<A>(args)...);
747 inline T& GetComponent(
entity_t local_id) {
748 assert(CorrectVersion(local_id));
749 return componentMap.at(
RavEngine::CTTI<T>()).template GetSet<T>()->GetComponent(local_id.id);
753 inline auto GetAllComponentsPolymorphic(
entity_t local_id){
754 assert(CorrectVersion(local_id));
755 return polymorphicQueryMap.at(CTTI<T>()).GetForEntity(local_id.id).template GetAll<T>();
759 inline bool HasComponent(
entity_t local_id) {
760 assert(CorrectVersion(local_id));
761 return componentMap.at(
RavEngine::CTTI<T>()).template GetSet<T>()->HasComponent(local_id.id);
765 inline bool HasComponentOfBase(
entity_t local_id){
766 assert(CorrectVersion(local_id));
767 return polymorphicQueryMap.at(CTTI<T>()).HasForEntity(local_id);
770 void DestroyStaticMeshRenderData(
const StaticMesh& mesh,
entity_t local_id);
771 void DestroySkinnedMeshRenderData(
const SkinnedMeshComponent& mesh,
entity_t local_id);
774 inline void DestroyComponent(
entity_t local_id){
778 if constexpr (std::is_same_v<T, StaticMesh>) {
780 auto& comp = setptr->GetComponent(local_id.id);
781 DestroyStaticMeshRenderData(comp, local_id);
783 else if constexpr (std::is_same_v<T, SkinnedMeshComponent>) {
784 auto& comp = setptr->GetComponent(local_id.id);
785 DestroySkinnedMeshRenderData(comp, local_id);
789 if constexpr (std::is_same_v<T, DirectionalLight>){
790 renderData.directionalLightData.EraseAtSparseIndex(local_id.id);
792 else if constexpr (std::is_same_v<T, AmbientLight>){
793 renderData.ambientLightData.EraseAtSparseIndex(local_id.id);
795 else if constexpr (std::is_same_v<T, PointLight>){
796 renderData.pointLightData.EraseAtSparseIndex(local_id.id);
798 else if constexpr (std::is_same_v<T, SpotLight>){
799 renderData.spotLightData.EraseAtSparseIndex(local_id.id);
801 else if constexpr (std::is_same_v<T, AudioSourceComponent>) {
802 destroyedAudioSources.enqueue(local_id.id);
804 else if constexpr (std::is_same_v<T, AudioMeshComponent>) {
805 destroyedMeshSources.enqueue(local_id.id);
809 setptr->Destroy(local_id.id);
811 if constexpr (HasQueryTypes<T>::value) {
813 const auto ids = T::GetQueryTypes();
814 for (
const auto id : ids) {
815 polymorphicQueryMap[id].template Destroy<T>(local_id.id);
821 inline EntitySparseSet<T>* GetRange(){
823 return set.template GetSet<T>();
826 template<
typename T,
bool isPolymorphic = false>
827 inline void FilterValidityCheck(entity_id_t
id,
void* set,
bool& satisfies)
const{
829 if constexpr (!isPolymorphic) {
830 satisfies = satisfies &&
static_cast<EntitySparseSet<T>*
>(set)->HasComponent(
id);
833 satisfies = satisfies &&
static_cast<SparseSetForPolymorphic*
>(set)->HasForEntity(
id);
838 inline T& FilterComponentGet(entity_id_t idx,
void* ptr){
839 return static_cast<EntitySparseSet<T>*
>(ptr)->GetComponent(idx);
843 inline auto FilterComponentBaseMultiGet(entity_id_t idx,
void* ptr) {
844 auto& c_ptr =
static_cast<SparseSetForPolymorphic*
>(ptr)->GetForEntity(idx);
845 return c_ptr.template GetAll<T>();
849 inline T& FilterComponentGetDirect(entity_id_t denseidx,
void* ptr){
850 return static_cast<EntitySparseSet<T>*
>(ptr)->Get(denseidx);
853 template<
typename T,
bool isPolymorphic = false>
854 inline void* FilterGetSparseSet(){
855 if constexpr (!isPolymorphic){
856 return MakeIfNotExists<T>();
859 return &polymorphicQueryMap[CTTI<T>()];
864 inline EntitySparseSet<T>* FilterGetSparseSetTyped(){
865 return MakeIfNotExists<T>();
870 template<
typename func,
bool polymorphic>
873 static constexpr bool isPolymorphic(){
878 template<
typename func,
bool polymorphic>
881 static constexpr bool isPolymorphic(){
886 template<
typename funcmode_t,
size_t n_types,
typename DataProv
iderType = DataProv
iderNone>
887 struct FilterOneMode{
888 using DataProvider_t = DataProviderType;
890 const std::array<void*,n_types>& ptrs;
891 FilterOneMode(funcmode_t& fm_i,
const std::array<void*,n_types>& ptrs_i, std::type_identity<DataProviderType>) : fm(fm_i),ptrs(ptrs_i){}
892 static constexpr decltype(n_types) nTypes(){
895 static constexpr bool isPolymorphic(){
896 return funcmode_t::isPolymorphic();
901 template<
typename funcmode_t,
size_t n_types,
typename DataProv
iderType = DataProv
iderNone>
902 struct FilterOneModeCopy{
903 using DataProvider_t = DataProviderType;
905 const std::array<void*,n_types> ptrs;
906 FilterOneModeCopy(
const funcmode_t& fm_i,
const std::array<void*, n_types>& ptrs_i, std::type_identity<DataProviderType>) : fm(fm_i), ptrs(ptrs_i) {}
907 static constexpr decltype(n_types) nTypes(){
910 static constexpr bool isPolymorphic(){
911 return funcmode_t::isPolymorphic();
915 template<
bool isPolymorphic,
typename ... A>
916 bool DoesEntitySatisfyFilter(entity_id_t owner,
const auto& pointerArray) {
917 bool satisfies =
true;
919 ((FilterValidityCheck<A, isPolymorphic>(owner, pointerArray[i], satisfies), i++), ...);
923 template<
typename prov
ider_t>
924 auto MakeEngineDataProvider(){
925 using nc_provider_t = std::remove_const_t<provider_t>;
926 nc_provider_t instance;
927 static_assert(not std::is_const_v<nc_provider_t>,
"Internal error: instance cannot be const!");
928 if constexpr (std::is_convertible_v<nc_provider_t, WorldDataProvider>) {
929 instance.world =
this;
934 template<
typename ... A,
typename filterone_t>
935 inline void FilterOne(filterone_t& fom, entity_id_t i){
936 using primary_t =
typename std::tuple_element<0, std::tuple<A...> >::type;
937 using dataProviderType = filterone_t::DataProvider_t;
938 if constexpr(filterone_t::nTypes() == 1){
939 if constexpr(!filterone_t::isPolymorphic()){
940 if constexpr (IsEngineDataProvider<dataProviderType>) {
941 auto dp = MakeEngineDataProvider<dataProviderType>();
942 fom.fm.f(dp, FilterComponentGetDirect<primary_t>(i, fom.ptrs[Index_v<primary_t, A...>]));
945 fom.fm.f(FilterComponentGetDirect<primary_t>(i, fom.ptrs[Index_v<primary_t, A...>]));
951 auto ptr_c =
static_cast<SparseSetForPolymorphic*
>(fom.ptrs[Index_v<primary_t, A...>]);
952 auto& indirection_obj = ptr_c->Get(i);
953 indirection_obj.for_each<primary_t>([&](
auto comp_ptr){
954 if constexpr (IsEngineDataProvider<dataProviderType>) {
955 auto dp = MakeEngineDataProvider<dataProviderType>();
956 fom.fm.f(dp, *comp_ptr);
966 if constexpr (!filterone_t::isPolymorphic()) {
967 owner =
static_cast<EntitySparseSet<primary_t>*
>(fom.ptrs[0])->GetOwner(i);
970 owner =
static_cast<SparseSetForPolymorphic*
>(fom.ptrs[0])->GetOwnerForDenseIdx(i).id;
972 if (EntityIsValid(owner)){
973 bool satisfies = DoesEntitySatisfyFilter<filterone_t::isPolymorphic(), A...>(owner, fom.ptrs);
975 if constexpr (!filterone_t::isPolymorphic()){
976 if constexpr (IsEngineDataProvider<dataProviderType>) {
977 auto dp = MakeEngineDataProvider<dataProviderType>();
978 fom.fm.f(dp, FilterComponentGet<A>(owner, fom.ptrs[Index_v<A, A...>])...);
981 fom.fm.f(FilterComponentGet<A>(owner, fom.ptrs[Index_v<A, A...>])...);
989 if constexpr (IsEngineDataProvider<dataProviderType>) {
990 auto dp = MakeEngineDataProvider<dataProviderType>();
991 fom.fm.f(dp, FilterComponentBaseMultiGet<A>(owner, fom.ptrs[Index_v<A, A...>])...);
994 fom.fm.f(FilterComponentBaseMultiGet<A>(owner, fom.ptrs[Index_v<A, A...>])...);
1003 template<
typename ... A,
typename funcmode>
1004 inline auto GenFilterData(
const funcmode& fn){
1005 constexpr auto n_types =
sizeof ... (A);
1006 static_assert(n_types > 0,
"Must supply a type to query for");
1008 using primary_t =
typename std::tuple_element<0, std::tuple<A...> >::type;
1011 std::array<void*, n_types> ptrs;
1013 inline auto getMainFilter()
const{
1014 if constexpr (!funcmode::isPolymorphic()){
1015 return static_cast<EntitySparseSet<primary_t>*
>(ptrs[0]);
1018 return static_cast<EntitySparseSet<PolymorphicIndirection>*
>(ptrs[0]);
1021 } data {FilterGetSparseSet<A,funcmode::isPolymorphic()>()...};
1028 template<
typename T>
1029 struct remove_polymorphic_arg {
1033 template <
typename T>
1034 struct remove_polymorphic_arg<PolymorphicGetResult<T, World::PolymorphicIndirection>> {
1037 template<
typename T>
using remove_polymorphic_arg_t =
typename remove_polymorphic_arg<T>::type;
1040 static_assert(std::is_same_v<remove_polymorphic_arg_t<float>, remove_polymorphic_arg_t<PolymorphicGetResult<float, World::PolymorphicIndirection>>>,
"template failed");
1042 template<
typename funcmode_t>
1043 inline void FilterGeneric(
const funcmode_t& fm) {
1044 using argtypes =
decltype(arguments(fm.f));
1046 [
this,&fm] <
typename... Ts>(std::type_identity<std::tuple<Ts...>>) ->
void
1048 using argtypes_noref = std::tuple<remove_polymorphic_arg_t<std::remove_const_t<std::remove_reference_t<Ts>>>...>;
1051 [
this,&fm]<
typename ... A>(std::type_identity<std::tuple<A...>>) ->
void
1053 auto fd = GenFilterData<A...>(fm);
1054 auto mainFilter = fd.getMainFilter();
1055 FilterOneMode fom(fm, fd.ptrs, std::type_identity<DataProviderNone>{});
1056 for (entity_id_t i = 0; i < mainFilter->DenseSize(); i++) {
1057 FilterOne<A...>(fom, i);
1059 }(std::type_identity<argtypes_noref>{});
1060 }(std::type_identity<argtypes>{});
1062 void NetworkingSpawn(ctti_t,Entity&);
1064 void SetupPerEntityRenderData(
entity_t);
1072 void SetEntityRenderlayer(
entity_t globalid, renderlayer_t layers);
1079 void SetEntityAttributes(
entity_t globalid, perobject_t attributes);
1085 perobject_t GetEntityAttributes(
entity_t globalid);
1092 template<
typename T,
typename ... A>
1094 auto id = CreateEntity();
1099 SetupPerEntityRenderData(
id);
1110 template<
typename func>
1119 template<
typename func>
1126 template<
typename func_t>
1136 constexpr static uint8_t id_size = 8;
1139 bool graphWasModified =
false;
1141 template<
bool isSerial,
bool polymorphic,
typename T,
typename ... Args>
1142 inline auto EmplaceSystemGeneric(Args&& ... args){
1143 graphWasModified =
true;
1144 using argtypes = functor_args_t<T>;
1150 [
this]<
typename T1,
typename... Ts>(std::type_identity<std::tuple<T1, Ts...>>,
auto&& ... args)
mutable ->
auto
1152 using argtypes_noref_noDP = std::tuple<remove_polymorphic_arg_t<std::remove_const_t<std::remove_reference_t<T1>>>,remove_polymorphic_arg_t<std::remove_const_t<std::remove_reference_t<Ts>>>...>;
1153 using argtypes_noref_DP = std::tuple<remove_polymorphic_arg_t<std::remove_const_t<std::remove_reference_t<Ts>>>...>;
1157 auto innerfn = [
this]<
typename ... A,
typename ... OrigTs,
class DataProviderT>(std::
type_identity<std::tuple<A...>>, std::type_identity<std::tuple<OrigTs...>>, std::type_identity<DataProviderT>, auto&& ... args) mutable -> auto
1162 auto ptr = &ecsRangeSizes[CTTI<T>()];
1164 FuncModeCopy<T,polymorphic> fm{T(std::forward<Args>(args)...)};
1166 auto fd = GenFilterData<A...>(fm);
1168 using DataProviderNCR = std::remove_reference_t<std::remove_const_t<DataProviderT>>;
1170 FilterOneModeCopy fom(std::move(fm), fd.ptrs, std::type_identity<DataProviderNCR>{});
1172 auto setptr = fd.getMainFilter();
1176 auto range_update = ECSTasks.emplace([
this,ptr,setptr](){
1177 *ptr =
static_cast<pos_t
>(setptr->DenseSize());
1178 }).name(Format(
"{} range update",type_name<T>()));
1181 std::optional<tf::Task> before, after;
1182 if constexpr (isSerial) {
1183 do_task = ECSTasks.emplace([
this, ptr, fom] ()
mutable {
1184 RVE_PROFILE_FN_N(type_name<T>().data());
1185 if constexpr (SystemHasBefore<T>) {
1186 fom.fm.f.before(
this);
1188 for (pos_t i = 0; i < std::ref(*ptr); i++) {
1189 FilterOne<A...>(fom, i);
1191 if constexpr (SystemHasAfter<T>) {
1192 fom.fm.f.after(
this);
1194 }).name(Format(
"{} serial", type_name<T>().data()));
1197 do_task = ECSTasks.for_each_index(pos_t(0), std::ref(*ptr), pos_t(1), [
this, fom](
auto i)
mutable {
1198 FilterOne<A...>(fom, i);
1199 }).name(Format(
"{}", type_name<T>().data()));
1200 if constexpr (SystemHasBefore<T>) {
1201 before.emplace(ECSTasks.emplace([fom,
this] {
1202 fom.fm.f.before(
this);
1203 }).name(Format(
"{}::before()", type_name<T>().data())));
1204 range_update.precede(before.value());
1205 do_task.succeed(before.value());
1207 if constexpr (SystemHasAfter<T>) {
1208 after.emplace(ECSTasks.emplace([fom,
this] {
1209 fom.fm.f.after(
this);
1210 }).name(Format(
"{}::after()", type_name<T>().data())));
1211 do_task.precede(after.value());
1215 range_update.precede(do_task);
1218 .rangeUpdate = range_update,
1223 if (typeToName.contains(CTTI<T>())) {
1224 Debug::Fatal(
"System {}/{} has already been loaded!",CTTI<T>(),type_name<T>());
1227 if constexpr (IsEngineDataProvider<DataProviderT> && std::is_convertible_v<DataProviderT, WorldDataProvider>) {
1229 static_assert(isSerial,
"Systems that use WorldDataProvider must be serial");
1230 tasks.usesWorldDataProvider =
true;
1233 typeToName[CTTI<T>()] = type_name<T>();
1235 constexpr static auto enterType = []<
typename pT>(std::vector<ctti_t>&reads, std::vector<ctti_t>&writes,
auto & typeToName) {
1236 using rpT = std::remove_reference_t<pT>;
1237 constexpr auto name = type_name<rpT>();
1238 constexpr auto name_system = type_name<T>();
1239 constexpr auto id = CTTI<rpT>();
1240 typeToName[id] = name;
1241 if constexpr (std::is_const_v<rpT>) {
1242 using nc_rpT = std::remove_const_t<rpT>;
1243 constexpr auto id = CTTI<nc_rpT>();
1244 typeToName[id] = name;
1245 reads.push_back(
id);
1248 writes.push_back(
id);
1251 (enterType.template operator()<OrigTs>(tasks.readDependencies, tasks.writeDependencies, typeToName), ...);
1253 if constexpr (IsEngineDataProvider<DataProviderT> && std::is_convertible_v<DataProviderT, ValidatorProviderBase>) {
1254 static_assert(isSerial,
"Systems that use Validators must be serial");
1257 auto enteryValidatorTypes = [
this, &tasks]<
typename ... vA>(std::type_identity<std::tuple<vA...>>) {
1258 (enterType.template operator() <vA> (tasks.readDependencies, tasks.writeDependencies, typeToName), ...);
1260 using validatorTupleType = DataProviderNCR::ValidatorType::types;
1261 enteryValidatorTypes(std::type_identity<validatorTupleType>{});
1264 typeToSystem[CTTI<T>()] = tasks;
1269 if constexpr (IsEngineDataProvider<T1>) {
1270 return innerfn(std::type_identity<argtypes_noref_DP>{}, std::type_identity<std::tuple<Ts...>>{}, std::type_identity<T1>{}, std::forward<Args>(args)...);
1273 return innerfn(std::type_identity<argtypes_noref_noDP>{}, std::type_identity<std::tuple<T1, Ts...>>{}, std::type_identity<DataProviderNone>{}, std::forward<Args>(args)...);
1276 }(std::type_identity<argtypes>{}, std::forward<Args>(args)...);
1279 template<
bool isSerial,
bool polymorphic,
typename T,
typename interval_t,
typename ... Args>
1280 inline void EmplaceTimedSystemGeneric(
const interval_t interval, Args&& ... args){
1281 auto task = EmplaceSystemGeneric<isSerial, polymorphic,T>(args...);
1283 auto c_interval = std::chrono::duration_cast<decltype(TimedSystemEntry::interval)>(interval);
1284 auto ts = &timedSystemRecords[CTTI<T>()];
1287 auto condition = ECSTasks.emplace([
this,ts,c_interval](){
1288 if (time_now - ts->last_timestamp > c_interval){
1289 ts->last_timestamp = time_now;
1293 }).name(
"Check time");
1294 condition.precede(task.rangeUpdate);
1297 void CheckSystems();
1303 template<
typename T,
typename U>
1310 if (
auto postHook =
uPair.postHook) {
1318 if (
auto preHook =
tPair.preHook) {
1326 graphWasModified =
true;
1332 template<
typename T>
1335 ECSTasks.erase(
tpair.rangeUpdate);
1336 ECSTasks.erase(
tpair.do_task);
1337 if (
auto before =
tpair.preHook) {
1338 ECSTasks.erase(before.value());
1340 if (
auto after =
tpair.postHook) {
1341 ECSTasks.erase(after.value());
1343 typeToSystem.erase(
CTTI<T>());
1352 template<
typename T,
typename ... Args>
1363 template<
typename T,
typename interval_t,
typename ... Args>
1372 template<
typename T,
typename ... Args>
1382 template<
typename T,
typename interval_t,
typename ... Args>
1391 template<
typename T,
typename ... Args>
1402 template<
typename T,
typename interval_t,
typename ... Args>
1411 template<
typename T,
typename ... Args>
1421 template<
typename T,
typename interval_t,
typename ... Args>
1426 const auto& getTypeToSystem()
const {
1427 return typeToSystem;
1430 std::atomic<bool> isRendering =
false;
1431 char worldIDbuf [id_size]{0};
1432 tf::Taskflow masterTasks;
1434 tf::Taskflow renderTasks;
1435 tf::Taskflow audioTasks;
1436 tf::Task audioTaskModule;
1438 tf::Taskflow ECSTasks;
1439 tf::Task ECSTaskModule;
1441 struct TypeErasureIterator{
1442 constexpr static auto size =
sizeof(EntitySparseSet<size_t>::const_iterator);
1447 template<
typename T>
1448 TypeErasureIterator(
const T begin,
const T end){
1450 new (begin)
decltype(begin)(begin);
1451 new (end)
decltype(end)(end);
1455 struct TimedSystemEntry{
1456 std::chrono::duration<double, std::micro> interval;
1457 std::chrono::time_point<e_clock_t> last_timestamp = e_clock_t::now();
1459 UnorderedNodeMap<ctti_t, TimedSystemEntry> timedSystemRecords;
1460 UnorderedNodeMap<ctti_t, pos_t> ecsRangeSizes;
1462 struct SystemTasks {
1463 tf::Task rangeUpdate, do_task;
1464 std::optional<tf::Task>preHook, postHook;
1465 std::vector<ctti_t> readDependencies;
1466 std::vector<ctti_t> writeDependencies;
1467 bool usesWorldDataProvider =
false;
1469 UnorderedMap<ctti_t, SystemTasks> typeToSystem;
1470 UnorderedMap<ctti_t, std::string_view> typeToName;
1472 void SetupTaskGraph();
1474 std::chrono::time_point<e_clock_t> time_now = e_clock_t::now();
1475 float currentFPSScale = 0.01f;
1478 struct dispatched_func{
1479 double runAtTime = 0;
1480 Function<void(
void)> func;
1481 dispatched_func(
const decltype(runAtTime) rt,
const decltype(func)& func) : func(func), runAtTime(rt){}
1482 dispatched_func(
const dispatched_func& other){
1483 runAtTime = other.runAtTime;
1488 UnorderedSet<std::shared_ptr<dispatched_func>> async_tasks;
1489 decltype(async_tasks)::iterator async_begin, async_end;
1494 friend class PhysicsLinkSystemWrite;
1495 std::unique_ptr<PhysicsSolver> Solver;
1501 LinkedList<InstantaneousAudioSourceToPlay> instantaneousToPlay;
1502 LinkedList<InstantaneousAmbientAudioSource> ambientToPlay;
1510 void TickECS(
float);
1513 void setupRenderTasks();
1522 bool physicsActive =
false;
1529 template<
typename T>
1534 std::string_view worldID{ worldIDbuf,id_size };
1535 std::atomic<bool> newFrame =
false;
1541 return currentFPSScale;
1548 masterTasks.dump(out);
1571 auto len = name.size();
1572 std::memcpy((
char*)worldID.data(), name.data(), std::min(
len,
static_cast<decltype(
len)
>(id_size)));
1591 inline void DeallocatePhysics();
1603 template<
typename T>
1614 void DispatchAsync(
const Function<
void(
void)>& func,
double delaySeconds);
1620 template<
typename T>
1623 if (componentMap.find(
CTTI<T>()) != componentMap.end()){