RavEngine
Loading...
Searching...
No Matches
World.hpp
1#pragma once
2//
3// World.hpp
4// RavEngine_Static
5//
6// Copyright © 2020 Ravbug.
7//
8
9#include "DataStructures.hpp"
10#include "Vector.hpp"
11#include "Queue.hpp"
12#include "Map.hpp"
13#include "SpinLock.hpp"
14#include <taskflow/taskflow.hpp>
15#include "Types.hpp"
16#include "PolymorphicIndirection.hpp"
17#include "SparseSet.hpp"
18#if !RVE_SERVER
19 #include "VRAMSparseSet.hpp"
20 #include "BuiltinMaterials.hpp"
21 #include "Light.hpp"
22 #include "BufferedVRAMVector.hpp"
23 #include "BufferPool.hpp"
24#else
25 #include "Ref.hpp"
26#endif
27#include "Debug.hpp"
28#include "Function.hpp"
29#include "Utilities.hpp"
30#include "CallableTraits.hpp"
31#include "Format.hpp"
32#include "Queue.hpp"
33#include "Layer.hpp"
34#include "Profile.hpp"
35#include "Validator.hpp"
36
37#if !RVE_SERVER
38namespace RavEngine {
39 struct MaterialSort {
41 MaterialSort(const decltype(mat)& mat) : mat(mat) {
42 assert(mat != nullptr);
43 }
44 bool operator<(const MaterialSort& other) const {
45 constexpr auto make128key = [](const auto & mat) {
46 using int128 = std::ranges::range_difference_t<std::ranges::iota_view<long long, long long>>;
47 // put priority in the high bits
48 int128 key = mat->GetPriority();
49 key <<= 64;
50 auto ptr = mat.get();
51 key |= uintptr_t(ptr);
52 return key;
53 };
54 auto key1 = make128key(mat);
55 auto key2 = make128key(other.mat);
56
57 return key1 < key2;
58 }
59 bool operator==(const MaterialSort& other) const = default;
60 };
61}
62
63namespace std {
64 template<>
65 struct hash<RavEngine::MaterialSort> {
66 inline size_t operator()(const RavEngine::MaterialSort& obj) {
67 return std::hash<decltype(obj.mat)>{}(obj.mat);
68 }
69 };
70}
71#endif
72
73namespace RavEngine {
74 struct Entity;
75 class InputManager;
76 struct Entity;
77 struct PhysicsCallback;
78 struct StaticMesh;
79 struct SkinnedMeshComponent;
80 struct RenderEngine;
81 struct Skybox;
82 struct PhysicsSolver;
83 class MeshAsset;
84 class MeshAssetSkinned;
85 class SkeletonAsset;
86 struct InstantaneousAudioSource;
87 struct InstantaneousAmbientAudioSource;
88 struct AudioSourceComponent;
89 struct InstantaneousAudioSourceToPlay;
90 struct AudioMeshComponent;
91 struct MeshCollectionStatic;
92 struct MeshCollectionSkinned;
93 struct SkyLight;
94 class World;
95
96 template <typename T, typename... Ts>
97 struct Index;
98
99 template <typename T, typename... Ts>
100 struct Index<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
101
102 template <typename T, typename U, typename... Ts>
103 struct Index<T, U, Ts...> : std::integral_constant<std::size_t, 1 + Index<T, Ts...>::value> {};
104
105 template <typename T, typename... Ts>
106 constexpr std::size_t Index_v = Index<T, Ts...>::value;
107
108 template <typename T>
110 {
111 private:
112 typedef char YesType[1];
113 typedef char NoType[2];
114
115 template <typename C> static YesType& test( decltype(&C::Destroy) ) ;
116 template <typename C> static NoType& test(...);
117
118
119 public:
120 enum { value = sizeof(test<T>(0)) == sizeof(YesType) };
121 };
122
123 template <typename T>
125 {
126 private:
127 typedef char YesType[1];
128 typedef char NoType[2];
129
130 template <typename C> static YesType& test( decltype(&C::GetQueryTypes) ) ;
131 template <typename C> static NoType& test(...);
132
133
134 public:
135 enum { value = sizeof(test<T>(0)) == sizeof(YesType) };
136 };
137
138 template<typename T>
139 concept SystemHasBefore = requires(T&& a) {
140 a.before((World*)nullptr);
141 };
142
143 template<typename T>
144 concept SystemHasAfter = requires(T && a) {
145 a.after((World*)nullptr);
146 };
147
149 World* world;
150 };
151
152 // used for is_convertible checks
154
155 template<typename ... A>
157 friend class World;
158 using ValidatorType = Validator<A...>;
159
160 ValidatorType validator;
161
162 // no copy
163 ValidatorProvider(const ValidatorProvider&) = delete;
164 void operator=(ValidatorProvider const&) = delete;
165 private:
166 // private move, private construct
169 };
170
171 // if the System does not need Engine data,
172 // the FuncMode will default to this type
174
175 template <typename T>
177 (std::is_convertible_v<T, WorldDataProvider> || std::is_convertible_v<T, ValidatorProviderBase>)
178 && not (std::is_convertible_v<T, DataProviderNone>);
179
180
181 class World : public std::enable_shared_from_this<World> {
182 friend class AudioPlayer;
183 friend class App;
184 friend class PhysicsBodyComponent;
185 Queue<entity_id_t> available;
186 Vector<uint8_t> versions;
187 pos_t numEntities = 0;
188 ConcurrentQueue<entity_id_t> destroyedAudioSources, destroyedMeshSources;
189
190 class InstantaneousAudioSourceFreeList {
191 entity_t nextID = {INVALID_ENTITY - 1};
193 public:
194 auto GetNextID() {
195 entity_t id;
196 if (freeList.try_dequeue(id)) {
197 return id;
198 }
199 else {
200 id = nextID;
201 nextID.id--;
202 }
203 return id;
204 }
205 void ReturnID(entity_t id) {
206 freeList.enqueue(id);
207 }
208 } instantaneousAudioSourceFreeList;
209
210 friend class Entity;
211 friend class Registry;
212 public:
213 template<typename T>
215 unordered_vector<T> dense_set;
217 Vector<entity_id_t> sparse_set{INVALID_ENTITY};
218
219 public:
220
221 using const_iterator = typename decltype(dense_set)::const_iterator_type;
222
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)...);
226 aux_set.emplace(local_id);
227 if (local_id >= sparse_set.size()){
228 sparse_set.resize(closest_multiple_of<int>(local_id+1,2),INVALID_ENTITY); //ensure there is enough space for this id
229 }
230
231 sparse_set[local_id] = static_cast<typename decltype(sparse_set)::value_type>(dense_set.size()-1);
232 return ret;
233 }
234
235 inline void Destroy(entity_id_t local_id){
236 assert(local_id < sparse_set.size());
237 assert(HasComponent(local_id)); // Cannot destroy a component on an entity that does not have one!
238 // call the destructor
239 if constexpr(HasDestroy<T>::value){
241 oldvalue.Destroy();
242 }
243 dense_set.erase(dense_set.begin() + sparse_set[local_id]);
244 aux_set.erase(aux_set.begin() + sparse_set[local_id]);
245
246 if (sparse_set[local_id] < aux_set.size()) { // did a move happen during this deletion?
247 // update the location it points
248 auto owner = aux_set[sparse_set[local_id]];
249 sparse_set[owner] = sparse_set[local_id];
250
251 }
252 sparse_set[local_id] = INVALID_INDEX;
253 }
254
255 inline T& GetComponent(entity_id_t local_id){
256 assert(HasComponent(local_id));
257 return dense_set[sparse_set[local_id]];
258 }
259
260 inline auto SparseToDense(entity_t local_id){
261 return sparse_set[local_id.id];
262 }
263
264 inline T& GetFirst(){
265 assert(!dense_set.empty());
266 return dense_set[0];
267 }
268
269 inline bool HasComponent(entity_id_t local_id) const{
270 return local_id < sparse_set.size() && sparse_set[local_id] != INVALID_ENTITY;
271 }
272
273 auto begin(){
274 return dense_set.begin();
275 }
276
277 auto end(){
278 return dense_set.end();
279 }
280
281 auto begin() const{
282 return dense_set.begin();
283 }
284
285 auto end() const{
286 return dense_set.end();
287 }
288
289 // get by dense index, not by entity ID
290 T& Get(entity_id_t idx){
291 return dense_set[idx];
292 }
293
294 auto GetOwner(entity_id_t idx) const{
295 return aux_set[idx];
296 }
297
298 auto DenseSize() const{
299 return dense_set.size();
300 }
301
302 auto GetDenseData() const{
303 return dense_set.data();
304 }
305
306 inline const decltype(dense_set)& GetDense() const{
307 return dense_set;
308 }
309 };
310 private:
311 class AnySparseSet{
312 constexpr static size_t buf_size = sizeof(EntitySparseSet<size_t>); // we use size_t here because all SparseSets are the same size
313 std::array<char, buf_size> buffer;
314 Function<void(AnySparseSet*,entity_t,World*)> _impl_destroyFn;
315 Function<void(AnySparseSet*)> _impl_deallocFn;
316 public:
317 // avoid capture overhead by wrapping
318 void destroyFn(entity_t id, World* world){
319 _impl_destroyFn(this, id, world);
320 }
321 void deallocFn(){
322 _impl_deallocFn(this);
323 }
324
325 template<typename T>
326 inline EntitySparseSet<T>* GetSet() {
327 return reinterpret_cast<EntitySparseSet<T>*>(buffer.data());
328 }
329
330 // the discard parameter is here to make the template work
331 template<typename T>
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);
337 }
338 }),
339 _impl_deallocFn([](AnySparseSet* thisptr) {
340 thisptr->GetSet<T>()->~EntitySparseSet<T>();
341 })
342 {
343 static_assert(sizeof(EntitySparseSet<T>) <= buf_size);
344 new (buffer.data()) EntitySparseSet<T>();
345 }
346
347 ~AnySparseSet() {
348 deallocFn();
349 }
350 };
351
352 locked_node_hashmap<RavEngine::ctti_t, AnySparseSet,SpinLock> componentMap;
353
354#if !RVE_SERVER
355 friend class StaticMesh;
356 friend class SkinnedMeshComponent;
357 friend class RenderEngine;
358 // renderer-friendly representation of static meshes
359 struct MDICommandBase {
360 RGLBufferPtr indirectBuffer, cullingBuffer, indirectStagingBuffer, cuboBuffer, cuboStagingBuffer;
361 ~MDICommandBase();
362 };
363
364 struct MDIICommand : public MDICommandBase {
365 struct command {
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) {
370 entities.Emplace(index, first_value);
371 }
372 };
374 };
375
376 struct MDIICommandSkinned : public MDICommandBase {
377 struct command {
379 WeakRef<SkeletonAsset> skeleton;
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) {
383 entities.Emplace(index, first_value);
384 }
385 };
387 };
388
389 struct DirLightUploadData {
390 glm::vec3 color;
391 glm::vec3 direction;
392 float intensity;
393 int castsShadows;
394 int shadowmapBindlessIndex[MAX_CASCADES]{0};
395 float cascadeDistances[MAX_CASCADES]{0};
396 renderlayer_t shadowLayers;
397 renderlayer_t illuminationLayers;
398 uint32_t numCascades;
399 };
400
401 struct DirLightUploadDataPassVarying{
402 glm::mat4 lightViewProj[MAX_CASCADES];
403 };
404
405 struct DirLightUploadDataPassVaryingHostOnly{
406 glm::mat4 lightview[MAX_CASCADES];
407 glm::mat4 lightProj[MAX_CASCADES];
408 };
409
410 struct AmbientLightUploadData{
411 glm::vec3 color;
412 float intensity;
413 renderlayer_t illuminationLayers;
414 uint32_t skyboxBindlessIndex = std::numeric_limits<uint32_t>::max();
415 uint32_t skyboxIrradianceBindlessIndex = std::numeric_limits<uint32_t>::max();
416 };
417
418 struct PointLightUploadData {
419 glm::mat4 viewMats[6];
420 glm::mat4 projMat;
421 glm::vec3 position;
422 glm::vec3 color;
423 float intensity;
424 int castsShadows;
425 renderlayer_t shadowLayers;
426 renderlayer_t illuminationLayers;
427 int shadowmapBindlessIndices[6]{ 0 };
428 };
429
430 struct SpotLightDataUpload {
431 glm::mat4 lightViewProj;
432 glm::mat4 worldTransform;
433 glm::vec3 color;
434 float intensity;
435 float coneAngle;
436 float penumbraAngle;
437 int castsShadows;
438 uint32_t shadowmapBindlessIndex;
439 renderlayer_t shadowLayers;
440 renderlayer_t illuminationLayers;
441 };
442
443 // data for the render engine
444 struct RenderData{
445
446 BufferedVRAMSparseSet<entity_id_t, DirLightUploadData> directionalLightData{"Directional Light Uniform Private Buffer"};
447
448 BufferedVRAMSparseSet<entity_id_t, AmbientLightUploadData> ambientLightData{"Ambient Light Private Buffer"};
449
450 BufferedVRAMSparseSet<entity_id_t, PointLightUploadData> pointLightData{"Point Light Private Buffer"};
451
452 BufferedVRAMSparseSet<entity_id_t, SpotLightDataUpload> spotLightData{"Point Light Private Buffer"};
453
454 BufferedVRAMVector<DirLightUploadDataPassVarying> directionalLightPassVarying{"Directional Light Pass Varying Buffer"};
455
456 Vector<DirLightUploadDataPassVaryingHostOnly> directionalLightPassVaryingHostOnly;
457
458 // uses world-local ID
459 BufferedVRAMVector<renderlayer_t> renderLayers{32};
460
461 BufferedVRAMVector<perobject_t> perObjectAttributes{ 32 };
462
463 // uses world-local ID
464
465 BufferedVRAMVector<matrix4> worldTransforms{"World Transform Private Buffer"};
466
467
468 OrderedMap<MaterialSort, MDIICommand> staticMeshRenderData;
469 OrderedMap<MaterialSort, MDIICommandSkinned> skinnedMeshRenderData;
470
471 RGLBufferPtr cuboBuffer;
472
473 SharedBufferPool stagingBufferPool;
474 };
475
476 RenderData renderData;
477
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*);
482#endif
483
484 public:
488 auto VersionForEntity(entity_id_t id) const{
489 return versions.at(id);
490 }
491
495 bool CorrectVersion(entity_t id) const{
496 return id.version == VersionForEntity(id.id);
497 }
498
500 struct elt{
501 Function<void*(entity_t)> getfn;
502 ctti_t full_id = 0;
503 template<typename T>
504 elt(World* world, T* discard) : full_id(CTTI<T>()){
505 auto setptr = world->componentMap.at(CTTI<T>()).template GetSet<T>();
506 getfn = [setptr](entity_t local_id) -> void*{
507 auto& thevalue = setptr->GetComponent(local_id.id);
508 return &(thevalue);
509 };
510 }
511
512 template<typename T>
513 T* Get(entity_t local_id){
514 return static_cast<T*>(getfn(local_id));
515 }
516
517 inline bool operator==(const elt& other) const{
518 return full_id == other.full_id;
519 }
520 };
522 entity_t owner = {INVALID_ENTITY};
523 World* world = nullptr;
524
525 template<typename T>
526 inline void push(){
527 T* discard = nullptr;
528 assert(std::find(elts.begin(),elts.end(),elt(world,discard)) ==elts.end()); // no duplicates
529 elts.emplace(world,discard);
530 }
531
532 template<typename T>
533 inline void erase(){
534 T* discard = nullptr;
535 elt value_erase(world,discard);
536 auto it = std::find(elts.begin(),elts.end(),value_erase);
537 assert(it != elts.end());
538 elts.erase(it);
539 }
540
541 inline bool empty() const{
542 return elts.empty();
543 }
544
545 PolymorphicIndirection(entity_t owner, World* world) : owner(owner), world(world){}
546
551 template<typename T, typename func_t>
552 inline void for_each(const func_t& f){
553 for(auto& e : elts){
554 auto ptr = e.Get<T>(owner);
555 f(ptr);
556 }
557 }
558
559 template<typename T>
560 inline auto GetAll() {
562 }
563
564 template<typename BaseIncludingArgument>
565 inline auto HandleFor(int idx){
566 auto& elt = elts.at(idx);
567 return BaseIncludingArgument({owner,world},elt.full_id);
568 }
569
570 auto begin(){
571 return elts.begin();
572 }
573 auto end(){
574 return elts.end();
575 }
576 auto begin() const{
577 return elts.begin();
578 }
579 auto end() const{
580 return elts.end();
581 }
582 };
583 private:
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};
589
590 public:
591
592 using const_iterator = typename decltype(dense_set)::const_iterator_type;
593
594 template<typename T>
595 inline void Emplace(entity_t local_id_in, World* world){
596 auto local_id = local_id_in.id;
597 //if a record for this does not exist, create it
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); //ensure there is enough space for this id
602 }
603 sparse_set[local_id] = static_cast<decltype(sparse_set)::value_type>(dense_set.size()-1);
604 }
605
606 // then push the Elt into it
607 GetForEntity(local_id).push<T>();
608 }
609
610 template<typename T>
611 inline void Destroy(entity_id_t local_id){
612 // get the record, then call erase on it
613 assert(HasForEntity(local_id));
614 GetForEntity(local_id).erase<T>();
615
616 // if that makes the container empty, then delete it from the Sets
617 if (GetForEntity(local_id).empty()){
618 auto denseidx = sparse_set[local_id];
619 dense_set.erase(dense_set.begin() + denseidx);
620
621 if (denseidx < dense_set.size()) { // did a move happen during this deletion?
622 auto ownerOfMoved = dense_set[denseidx].owner;
623 sparse_set[ownerOfMoved.id] = denseidx;
624 }
625 sparse_set[local_id] = INVALID_INDEX;
626 }
627 }
628
629 inline U& GetForEntity(entity_id_t local_id){
630 assert(HasForEntity(local_id));
631 return dense_set[sparse_set[local_id]];
632 }
633
634 inline auto SparseToDense(entity_id_t local_id){
635 return sparse_set[local_id];
636 }
637
638 inline auto GetOwnerForDenseIdx(entity_id_t dense_idx) {
639 assert(dense_idx < dense_set.size());
640 // get the indirection object which is storing the owner
641 return dense_set[dense_idx].owner;
642 }
643
644
645 inline bool HasForEntity(entity_id_t local_id) const{
646 return local_id < sparse_set.size() && sparse_set[local_id] != INVALID_ENTITY;
647 }
648
649 auto begin(){
650 return dense_set.begin();
651 }
652
653 auto end(){
654 return dense_set.end();
655 }
656
657 auto begin() const{
658 return dense_set.begin();
659 }
660
661 auto end() const{
662 return dense_set.end();
663 }
664
665 // get by dense index, not by entity ID
666 U& Get(entity_id_t idx){
667 return dense_set[idx];
668 }
669
670 auto DenseSize() const{
671 return dense_set.size();
672 }
673
674 auto GetDenseData() const{
675 return dense_set.data();
676 }
677
678 inline const decltype(dense_set)& GetDense() const{
679 return dense_set;
680 }
681 };
682
683 UnorderedNodeMap<ctti_t,SparseSetForPolymorphic> polymorphicQueryMap;
684
685 inline void DestroyEntity(entity_t local_id){
686 // go down the list of all component types registered in this world
687 // and call destroy if the entity has that component type
688 // possible optimization: vector of vector<ctti_t> to make this faster?
689 NetworkingDestroy(local_id);
690 for(auto& pair : componentMap){
691 pair.second.destroyFn(local_id,this);
692 }
693 // unset localToGlobal
694 available.push(local_id.id);
695 versions[local_id.id]++; // we increment it here so that if we have a use-after free, it's detected before the ID is recycled
696 }
697
698 template<typename T>
699 inline EntitySparseSet<T>* MakeIfNotExists(){
700 return (*componentMap.try_emplace(RavEngine::CTTI<T>(),static_cast<T*>(nullptr)).first).second.template GetSet<T>();
701 }
702
703 struct EntityRedir{
704 World* owner;
705 entity_t id;
706 operator Entity() const;
707 };
708
709 template<typename T, typename ... A>
710 inline T& EmplaceComponent(entity_t local_id, A&& ... args){
711 auto ptr = MakeIfNotExists<T>();
712 //constexpr bool isMoving = sizeof ... (A) == 1; && (std::is_rvalue_reference<typename std::tuple_element<0, std::tuple<A...>>::type>::value || std::is_lvalue_reference<typename std::tuple_element<0, std::tuple<A...>>::type>::value);
713
714 // does this component have alternate query types
715 if constexpr (HasQueryTypes<T>::value){
716 // polymorphic recordkeep
717 const auto ids = T::GetQueryTypes();
718 for(const auto id : ids){
719 polymorphicQueryMap[id].template Emplace<T>(local_id, this);
720 }
721 }
722#if !RVE_SERVER
723 // if it's a light, register it in the container
724 if constexpr (std::is_same_v<T, DirectionalLight>){
725 renderData.directionalLightData.Emplace(local_id.id);
726 }
727 else if constexpr (std::is_same_v<T, AmbientLight>){
728 renderData.ambientLightData.Emplace(local_id.id);
729 }
730 else if constexpr (std::is_same_v<T, PointLight>){
731 renderData.pointLightData.Emplace(local_id.id);
732 }
733 else if constexpr (std::is_same_v<T, SpotLight>){
734 renderData.spotLightData.Emplace(local_id.id);
735 }
736#endif
737 //detect if T constructor's first argument is an Entity, if it is, then we need to pass that before args (pass local_id again)
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)...);
740 }
741 else{
742 return ptr->Emplace(local_id.id,std::forward<A>(args)...);
743 }
744 }
745
746 template<typename T>
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);
750 }
751
752 template<typename T>
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>();
756 }
757
758 template<typename 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);
762 }
763
764 template<typename T>
765 inline bool HasComponentOfBase(entity_t local_id){
766 assert(CorrectVersion(local_id));
767 return polymorphicQueryMap.at(CTTI<T>()).HasForEntity(local_id);
768 }
769
770 void DestroyStaticMeshRenderData(const StaticMesh& mesh, entity_t local_id);
771 void DestroySkinnedMeshRenderData(const SkinnedMeshComponent& mesh, entity_t local_id);
772
773 template<typename T>
774 inline void DestroyComponent(entity_t local_id){
775
776 auto setptr = componentMap.at(RavEngine::CTTI<T>()).template GetSet<T>();
777
778 if constexpr (std::is_same_v<T, StaticMesh>) {
779 // remove the entry from the render data structure
780 auto& comp = setptr->GetComponent(local_id.id);
781 DestroyStaticMeshRenderData(comp, local_id);
782 }
783 else if constexpr (std::is_same_v<T, SkinnedMeshComponent>) {
784 auto& comp = setptr->GetComponent(local_id.id);
785 DestroySkinnedMeshRenderData(comp, local_id);
786 }
787#if !RVE_SERVER
788 // if it's a light, register it in the container
789 if constexpr (std::is_same_v<T, DirectionalLight>){
790 renderData.directionalLightData.EraseAtSparseIndex(local_id.id);
791 }
792 else if constexpr (std::is_same_v<T, AmbientLight>){
793 renderData.ambientLightData.EraseAtSparseIndex(local_id.id);
794 }
795 else if constexpr (std::is_same_v<T, PointLight>){
796 renderData.pointLightData.EraseAtSparseIndex(local_id.id);
797 }
798 else if constexpr (std::is_same_v<T, SpotLight>){
799 renderData.spotLightData.EraseAtSparseIndex(local_id.id);
800 }
801 else if constexpr (std::is_same_v<T, AudioSourceComponent>) {
802 destroyedAudioSources.enqueue(local_id.id);
803 }
804 else if constexpr (std::is_same_v<T, AudioMeshComponent>) {
805 destroyedMeshSources.enqueue(local_id.id);
806 }
807#endif
808
809 setptr->Destroy(local_id.id);
810 // does this component have alternate query types
811 if constexpr (HasQueryTypes<T>::value) {
812 // polymorphic recordkeep
813 const auto ids = T::GetQueryTypes();
814 for (const auto id : ids) {
815 polymorphicQueryMap[id].template Destroy<T>(local_id.id);
816 }
817 }
818 }
819
820 template<typename T>
821 inline EntitySparseSet<T>* GetRange(){
822 auto& set = componentMap.at(RavEngine::CTTI<T>());
823 return set.template GetSet<T>();
824 }
825
826 template<typename T, bool isPolymorphic = false>
827 inline void FilterValidityCheck(entity_id_t id, void* set, bool& satisfies) const{
828 // in this order so that the first one the entity does not have aborts the rest of them
829 if constexpr (!isPolymorphic) {
830 satisfies = satisfies && static_cast<EntitySparseSet<T>*>(set)->HasComponent(id);
831 }
832 else {
833 satisfies = satisfies && static_cast<SparseSetForPolymorphic*>(set)->HasForEntity(id);
834 }
835 }
836
837 template<typename T>
838 inline T& FilterComponentGet(entity_id_t idx, void* ptr){
839 return static_cast<EntitySparseSet<T>*>(ptr)->GetComponent(idx);
840 }
841
842 template<typename T>
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>();
846 }
847
848 template<typename T>
849 inline T& FilterComponentGetDirect(entity_id_t denseidx, void* ptr){
850 return static_cast<EntitySparseSet<T>*>(ptr)->Get(denseidx);
851 }
852
853 template<typename T, bool isPolymorphic = false>
854 inline void* FilterGetSparseSet(){
855 if constexpr (!isPolymorphic){
856 return MakeIfNotExists<T>();
857 }
858 else{
859 return &polymorphicQueryMap[CTTI<T>()];
860 }
861 }
862
863 template<typename T>
864 inline EntitySparseSet<T>* FilterGetSparseSetTyped(){
865 return MakeIfNotExists<T>();
866 }
867
868 entity_t CreateEntity();
869
870 template<typename func, bool polymorphic>
871 struct FuncMode{
872 func& f;
873 static constexpr bool isPolymorphic(){
874 return polymorphic;
875 }
876 };
877
878 template<typename func, bool polymorphic>
879 struct FuncModeCopy{
880 func f;
881 static constexpr bool isPolymorphic(){
882 return polymorphic;
883 }
884 };
885
886 template<typename funcmode_t, size_t n_types, typename DataProviderType = DataProviderNone>
887 struct FilterOneMode{
888 using DataProvider_t = DataProviderType;
889 funcmode_t& fm;
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(){
893 return n_types;
894 }
895 static constexpr bool isPolymorphic(){
896 return funcmode_t::isPolymorphic();
897 }
898 };
899
900 // for when the object needs to own the data, for outliving scopes
901 template<typename funcmode_t, size_t n_types, typename DataProviderType = DataProviderNone>
902 struct FilterOneModeCopy{
903 using DataProvider_t = DataProviderType;
904 funcmode_t fm;
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(){
908 return n_types;
909 }
910 static constexpr bool isPolymorphic(){
911 return funcmode_t::isPolymorphic();
912 }
913 };
914
915 template< bool isPolymorphic, typename ... A>
916 bool DoesEntitySatisfyFilter(entity_id_t owner, const auto& pointerArray) {
917 bool satisfies = true;
918 uint32_t i = 0;
919 ((FilterValidityCheck<A, isPolymorphic>(owner, pointerArray[i], satisfies), i++), ...);
920 return satisfies;
921 }
922
923 template<typename provider_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;
930 }
931 return instance;
932 };
933
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...>]));
943 }
944 else {
945 fom.fm.f(FilterComponentGetDirect<primary_t>(i, fom.ptrs[Index_v<primary_t, A...>]));
946 }
947
948 }
949 else{
950 //polymorphic query needs to be handled differently, because there can be multiple of a type on an entity
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);
957 }
958 else {
959 fom.fm.f(*comp_ptr);
960 }
961 });
962 }
963 }
964 else{
965 entity_id_t owner;
966 if constexpr (!filterone_t::isPolymorphic()) {
967 owner = static_cast<EntitySparseSet<primary_t>*>(fom.ptrs[0])->GetOwner(i);
968 }
969 else {
970 owner = static_cast<SparseSetForPolymorphic*>(fom.ptrs[0])->GetOwnerForDenseIdx(i).id;
971 }
972 if (EntityIsValid(owner)){
973 bool satisfies = DoesEntitySatisfyFilter<filterone_t::isPolymorphic(), A...>(owner, fom.ptrs);
974 if (satisfies){
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...>])...);
979 }
980 else {
981 fom.fm.f(FilterComponentGet<A>(owner, fom.ptrs[Index_v<A, A...>])...);
982 }
983
984 }
985 else{
986 // Because there can be multiple base types per entity, per each Filter type in A,
987 // the user's function must take vectors of A, and decide how to process
988 // multi-case
989 if constexpr (IsEngineDataProvider<dataProviderType>) {
990 auto dp = MakeEngineDataProvider<dataProviderType>();
991 fom.fm.f(dp, FilterComponentBaseMultiGet<A>(owner, fom.ptrs[Index_v<A, A...>])...);
992 }
993 else {
994 fom.fm.f(FilterComponentBaseMultiGet<A>(owner, fom.ptrs[Index_v<A, A...>])...);
995 }
996
997 }
998 }
999 }
1000 }
1001 }
1002
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");
1007
1008 using primary_t = typename std::tuple_element<0, std::tuple<A...> >::type;
1009
1010 struct FilterData{
1011 std::array<void*, n_types> ptrs;
1012
1013 inline auto getMainFilter() const{
1014 if constexpr (!funcmode::isPolymorphic()){
1015 return static_cast<EntitySparseSet<primary_t>*>(ptrs[0]);
1016 }
1017 else{
1018 return static_cast<EntitySparseSet<PolymorphicIndirection>*>(ptrs[0]);
1019 }
1020 }
1021 } data {FilterGetSparseSet<A,funcmode::isPolymorphic()>()...};
1022
1023 return data;
1024 }
1025
1026 // CTTI calls will fail on Polymorphic arguments, so
1027 // need to extract their inner types
1028 template<typename T>
1029 struct remove_polymorphic_arg {
1030 using type = T;
1031 };
1032
1033 template <typename T>
1034 struct remove_polymorphic_arg<PolymorphicGetResult<T, World::PolymorphicIndirection>> {
1035 using type = T;
1036 };
1037 template<typename T> using remove_polymorphic_arg_t = typename remove_polymorphic_arg<T>::type;
1038
1039 // "unit test" to sanity check the templates above
1040 static_assert(std::is_same_v<remove_polymorphic_arg_t<float>, remove_polymorphic_arg_t<PolymorphicGetResult<float, World::PolymorphicIndirection>>>, "template failed");
1041
1042 template<typename funcmode_t>
1043 inline void FilterGeneric(const funcmode_t& fm) {
1044 using argtypes = decltype(arguments(fm.f));
1045 // step 1: get it as types
1046 [this,&fm] <typename... Ts>(std::type_identity<std::tuple<Ts...>>) -> void
1047 {
1048 using argtypes_noref = std::tuple<remove_polymorphic_arg_t<std::remove_const_t<std::remove_reference_t<Ts>>>...>;
1049 // step 2: get it as non-reference types, and slice off the first argument
1050 // because it's a float and we don't want it
1051 [this,&fm]<typename ... A>(std::type_identity<std::tuple<A...>>) -> void
1052 {
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);
1058 }
1059 }(std::type_identity<argtypes_noref>{});
1060 }(std::type_identity<argtypes>{});
1061 }
1062 void NetworkingSpawn(ctti_t,Entity&);
1063 void NetworkingDestroy(entity_t);
1064 void SetupPerEntityRenderData(entity_t);
1065 public:
1066
1072 void SetEntityRenderlayer(entity_t globalid, renderlayer_t layers);
1073
1079 void SetEntityAttributes(entity_t globalid, perobject_t attributes);
1080
1085 perobject_t GetEntityAttributes(entity_t globalid);
1086
1092 template<typename T, typename ... A>
1093 inline T Instantiate(A&& ... args){
1094 auto id = CreateEntity();
1095 T en;
1096 en.id = id;
1097 en.world = this;
1098#if !RVE_SERVER
1099 SetupPerEntityRenderData(id);
1100#endif
1101 en.Create(args...);
1102 NetworkingSpawn(CTTI<T>(),en);
1103 return en;
1104 }
1105
1110 template<typename func>
1111 inline void Filter(func&& f){
1112 FilterGeneric(FuncMode<func, false>{ f });
1113 }
1114
1119 template<typename func>
1120 inline void FilterPolymorphic(func&& f){
1121 FilterGeneric(FuncMode<func, true>{ f });
1122 }
1123
1124 // this does not check if the entity actually has the component
1125 // instead it iterates over keys in the hashtable
1126 template<typename func_t>
1127 inline void EnumerateComponentsOn(entity_t local_id, const func_t& fn){
1128 for(auto& componentRow : componentMap){
1129 auto& sp_erased = componentRow.second;
1130 fn(sp_erased);
1131 }
1132 }
1133
1134 virtual ~World();
1135
1136 constexpr static uint8_t id_size = 8;
1137 Ref<Skybox> skybox;
1138 private:
1139 bool graphWasModified = false;
1140
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>;
1145
1146
1147
1148 return
1149 // step 1: get it as types
1150 [this]<typename T1, typename... Ts>(std::type_identity<std::tuple<T1, Ts...>>, auto&& ... args) mutable -> auto
1151 {
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>>>...>;
1154 // step 2: get it as non-reference types, and slice off the first argument
1155 // if it is an engine data provider
1156
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
1158 {
1159
1160 // use `A...` here
1161
1162 auto ptr = &ecsRangeSizes[CTTI<T>()];
1163
1164 FuncModeCopy<T,polymorphic> fm{T(std::forward<Args>(args)...)};
1165
1166 auto fd = GenFilterData<A...>(fm);
1167
1168 using DataProviderNCR = std::remove_reference_t<std::remove_const_t<DataProviderT>>;
1169
1170 FilterOneModeCopy fom(std::move(fm), fd.ptrs, std::type_identity<DataProviderNCR>{});
1171
1172 auto setptr = fd.getMainFilter();
1173
1174
1175 // value update
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>()));
1179
1180 tf::Task do_task;
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);
1187 }
1188 for (pos_t i = 0; i < std::ref(*ptr); i++) {
1189 FilterOne<A...>(fom, i);
1190 }
1191 if constexpr (SystemHasAfter<T>) {
1192 fom.fm.f.after(this);
1193 }
1194 }).name(Format("{} serial", type_name<T>().data()));
1195 }
1196 else {
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());
1206 }
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());
1212 }
1213 }
1214
1215 range_update.precede(do_task);
1216
1217 SystemTasks tasks{
1218 .rangeUpdate = range_update,
1219 .do_task = do_task,
1220 .preHook = before,
1221 .postHook = after
1222 };
1223 if (typeToName.contains(CTTI<T>())) {
1224 Debug::Fatal("System {}/{} has already been loaded!",CTTI<T>(),type_name<T>());
1225 };
1226
1227 if constexpr (IsEngineDataProvider<DataProviderT> && std::is_convertible_v<DataProviderT, WorldDataProvider>) {
1228 // validate: if the system uses the WorldProvider, it must be a serial system
1229 static_assert(isSerial, "Systems that use WorldDataProvider must be serial");
1230 tasks.usesWorldDataProvider = true;
1231 }
1232
1233 typeToName[CTTI<T>()] = type_name<T>();
1234 // enter parameter types into tracking structure
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);
1246 }
1247 else {
1248 writes.push_back(id);
1249 }
1250 };
1251 (enterType.template operator()<OrigTs>(tasks.readDependencies, tasks.writeDependencies, typeToName), ...);
1252
1253 if constexpr (IsEngineDataProvider<DataProviderT> && std::is_convertible_v<DataProviderT, ValidatorProviderBase>) {
1254 static_assert(isSerial, "Systems that use Validators must be serial");
1255
1256 // add validator types to the tracking structure
1257 auto enteryValidatorTypes = [this, &tasks]<typename ... vA>(std::type_identity<std::tuple<vA...>>) {
1258 (enterType.template operator() <vA> (tasks.readDependencies, tasks.writeDependencies, typeToName), ...);
1259 };
1260 using validatorTupleType = DataProviderNCR::ValidatorType::types;
1261 enteryValidatorTypes(std::type_identity<validatorTupleType>{});
1262 }
1263
1264 typeToSystem[CTTI<T>()] = tasks;
1265 return tasks;
1266
1267 };
1268 // based on if the system needs a dataprovider as arg 0
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)...);
1271 }
1272 else {
1273 return innerfn(std::type_identity<argtypes_noref_noDP>{}, std::type_identity<std::tuple<T1, Ts...>>{}, std::type_identity<DataProviderNone>{}, std::forward<Args>(args)...);
1274 }
1275
1276 }(std::type_identity<argtypes>{}, std::forward<Args>(args)...);
1277 }
1278
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...);
1282
1283 auto c_interval = std::chrono::duration_cast<decltype(TimedSystemEntry::interval)>(interval);
1284 auto ts = &timedSystemRecords[CTTI<T>()];
1285
1286 //conditional task - returns out-of-range if condition fails so that the task does not run
1287 auto condition = ECSTasks.emplace([this,ts,c_interval](){
1288 if (time_now - ts->last_timestamp > c_interval){
1289 ts->last_timestamp = time_now;
1290 return 0;
1291 }
1292 return 1;
1293 }).name("Check time");
1294 condition.precede(task.rangeUpdate);
1295 }
1296
1297 void CheckSystems();
1298
1299 public:
1303 template<typename T, typename U>
1304 inline void CreateDependency(){
1305 // T depends on (runs after) U
1306 auto& tPair = typeToSystem.at(CTTI<T>());
1307 auto& uPair = typeToSystem.at(CTTI<U>());
1308
1309 tf::Task dependecyRoot;
1310 if (auto postHook = uPair.postHook) {
1311 dependecyRoot = postHook.value();
1312 }
1313 else {
1314 dependecyRoot = uPair.do_task;
1315 }
1316
1317 tf::Task dependencyLeaf;
1318 if (auto preHook = tPair.preHook) {
1319 dependencyLeaf = preHook.value();
1320 }
1321 else {
1322 dependencyLeaf = tPair.do_task;
1323 }
1324
1326 graphWasModified = true;
1327 }
1328
1332 template<typename T>
1334 auto& tpair = typeToSystem.at(CTTI<T>());
1335 ECSTasks.erase(tpair.rangeUpdate);
1336 ECSTasks.erase(tpair.do_task);
1337 if (auto before = tpair.preHook) {
1338 ECSTasks.erase(before.value());
1339 }
1340 if (auto after = tpair.postHook) {
1341 ECSTasks.erase(after.value());
1342 }
1343 typeToSystem.erase(CTTI<T>());
1344
1345 // graphWasModified is not set to true here, because removing systems cannot introduce new hazards to an already-safe graph.
1346 }
1347
1352 template<typename T, typename ... Args>
1353 auto EmplaceSystem(Args&& ... args) {
1354 return EmplaceSystemGeneric<false, false, T>(std::forward<Args>(args)...);
1355 }
1356
1363 template<typename T, typename interval_t, typename ... Args>
1364 auto EmplaceTimedSystem(const interval_t interval, Args&& ... args){
1365 return EmplaceTimedSystemGeneric<false, false,T>(interval, std::forward<Args>(args)...);
1366 }
1367
1372 template<typename T, typename ... Args>
1373 auto EmplacePolymorphicSystem(Args&& ... args){
1374 return EmplaceSystemGeneric<false,true,T>(std::forward<Args>(args)...);
1375 }
1376
1382 template<typename T, typename interval_t, typename ... Args>
1383 auto EmplacePolymorphicTimedSystem(const interval_t interval, Args&& ... args){
1384 return EmplaceTimedSystemGeneric<true, true,T>(interval, std::forward<Args>(args)...);
1385 }
1386
1391 template<typename T, typename ... Args>
1392 auto EmplaceSerialSystem(Args&& ... args) {
1393 return EmplaceSystemGeneric<true, false, T>(std::forward<Args>(args)...);
1394 }
1395
1402 template<typename T, typename interval_t, typename ... Args>
1403 auto EmplaceSerialTimedSystem(const interval_t interval, Args&& ... args) {
1404 return EmplaceTimedSystemGeneric<true, false, T>(interval, std::forward<Args>(args)...);
1405 }
1406
1411 template<typename T, typename ... Args>
1412 auto EmplaceSerialPolymorphicSystem(Args&& ... args) {
1413 return EmplaceSystemGeneric<true, true, T>(std::forward<Args>(args)...);
1414 }
1415
1421 template<typename T, typename interval_t, typename ... Args>
1422 auto EmplaceSerialPolymorphicTimedSystem(const interval_t interval, Args&& ... args) {
1423 return EmplaceTimedSystemGeneric<true, true, T>(interval, std::forward<Args>(args)...);
1424 }
1425
1426 const auto& getTypeToSystem() const {
1427 return typeToSystem;
1428 }
1429 private:
1430 std::atomic<bool> isRendering = false;
1431 char worldIDbuf [id_size]{0};
1432 tf::Taskflow masterTasks;
1433#if !RVE_SERVER
1434 tf::Taskflow renderTasks;
1435 tf::Taskflow audioTasks;
1436 tf::Task audioTaskModule;
1437#endif
1438 tf::Taskflow ECSTasks;
1439 tf::Task ECSTaskModule;
1440
1441 struct TypeErasureIterator{
1442 constexpr static auto size = sizeof(EntitySparseSet<size_t>::const_iterator);
1443
1444 char begin[size];
1445 char end[size];
1446
1447 template<typename T>
1448 TypeErasureIterator(const T begin, const T end){
1449 // copy-construct into the buffers
1450 new (begin) decltype(begin)(begin);
1451 new (end) decltype(end)(end);
1452 }
1453 };
1454
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();
1458 };
1459 UnorderedNodeMap<ctti_t, TimedSystemEntry> timedSystemRecords;
1460 UnorderedNodeMap<ctti_t, pos_t> ecsRangeSizes;
1461
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;
1468 };
1469 UnorderedMap<ctti_t, SystemTasks> typeToSystem;
1470 UnorderedMap<ctti_t, std::string_view> typeToName;
1471
1472 void SetupTaskGraph();
1473
1474 std::chrono::time_point<e_clock_t> time_now = e_clock_t::now();
1475 float currentFPSScale = 0.01f;
1476
1477 //Entity list
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;
1484 func = other.func;
1485 }
1486 dispatched_func(){}
1487 };
1488 UnorderedSet<std::shared_ptr<dispatched_func>> async_tasks;
1489 decltype(async_tasks)::iterator async_begin, async_end;
1491 protected:
1492
1493 //physics system
1494 friend class PhysicsLinkSystemWrite;
1495 std::unique_ptr<PhysicsSolver> Solver;
1496
1497 //fire-and-forget audio
1498#if !RVE_SERVER
1499
1500
1501 LinkedList<InstantaneousAudioSourceToPlay> instantaneousToPlay;
1502 LinkedList<InstantaneousAmbientAudioSource> ambientToPlay;
1503#endif
1504
1509 virtual void PreTick(float fpsScale) {}
1510 void TickECS(float);
1511#if !RVE_SERVER
1512
1513 void setupRenderTasks();
1514#endif
1515
1520 virtual void PostTick(float fpsScale) {}
1521
1522 bool physicsActive = false;
1523
1524 public:
1525
1529 template<typename T>
1530 inline T& GetComponent(){
1531 return componentMap.at(RavEngine::CTTI<T>()).template GetSet<T>()->GetFirst();
1532 }
1533
1534 std::string_view worldID{ worldIDbuf,id_size };
1535 std::atomic<bool> newFrame = false;
1536
1540 inline float GetCurrentFPSScale() const {
1541 return currentFPSScale;
1542 }
1543
1547 inline void ExportTaskGraph(std::ostream& out){
1548 masterTasks.dump(out);
1549 }
1550
1555 bool InitPhysics();
1556
1562 void Tick(float);
1563
1564 World();
1565
1570 World(const std::string& name) : World(){
1571 auto len = name.size();
1572 std::memcpy((char*)worldID.data(), name.data(), std::min(len,static_cast<decltype(len)>(id_size)));
1573 }
1574
1579 World(const decltype(skybox)& sk) : World() {
1580 skybox = sk;
1581 }
1582#if !RVE_SERVER
1583 void PlaySound(const InstantaneousAudioSource& ias);
1584
1585 void PlayAmbientSound(const InstantaneousAmbientAudioSource& iaas);
1586#endif
1587
1591 inline void DeallocatePhysics();
1592
1596 virtual void OnActivate() {}
1597
1601 virtual void OnDeactivate() {}
1602
1603 template<typename T>
1604 static inline PointerInputBinder<T> GetInput(T* ptr){
1605 return PointerInputBinder<T>(ptr);
1606 }
1607
1614 void DispatchAsync(const Function<void(void)>& func, double delaySeconds);
1615
1620 template<typename T>
1622 EntitySparseSet<T>* ret = nullptr;
1623 if (componentMap.find(CTTI<T>()) != componentMap.end()){
1624 ret = GetRange<T>();
1625 }
1626 return ret;
1627 }
1628 };
1629}
Definition App.hpp:43
Definition AudioPlayer.hpp:27
static void Fatal(const std::string_view message)
Definition Debug.hpp:106
Definition World.hpp:110
Definition World.hpp:125
Definition PhysicsBodyComponent.hpp:41
Definition World.hpp:214
Definition World.hpp:181
auto VersionForEntity(entity_id_t id) const
Definition World.hpp:488
auto EmplaceTimedSystem(const interval_t interval, Args &&... args)
Definition World.hpp:1364
void ExportTaskGraph(std::ostream &out)
Definition World.hpp:1547
T & GetComponent()
Definition World.hpp:1530
auto EmplacePolymorphicTimedSystem(const interval_t interval, Args &&... args)
Definition World.hpp:1383
void CreateDependency()
Definition World.hpp:1304
auto EmplaceSerialPolymorphicSystem(Args &&... args)
Definition World.hpp:1412
void Filter(func &&f)
Definition World.hpp:1111
bool CorrectVersion(entity_t id) const
Definition World.hpp:495
virtual void OnActivate()
Definition World.hpp:1596
World(const decltype(skybox)&sk)
Definition World.hpp:1579
virtual void PreTick(float fpsScale)
Definition World.hpp:1509
void FilterPolymorphic(func &&f)
Definition World.hpp:1120
auto EmplaceSerialTimedSystem(const interval_t interval, Args &&... args)
Definition World.hpp:1403
auto EmplaceSystem(Args &&... args)
Definition World.hpp:1353
World(const std::string &name)
Definition World.hpp:1570
virtual void OnDeactivate()
Definition World.hpp:1601
auto EmplacePolymorphicSystem(Args &&... args)
Definition World.hpp:1373
float GetCurrentFPSScale() const
Definition World.hpp:1540
auto EmplaceSerialPolymorphicTimedSystem(const interval_t interval, Args &&... args)
Definition World.hpp:1422
virtual void PostTick(float fpsScale)
Definition World.hpp:1520
auto EmplaceSerialSystem(Args &&... args)
Definition World.hpp:1392
auto GetAllComponentsOfType()
Definition World.hpp:1621
T Instantiate(A &&... args)
Definition World.hpp:1093
void RemoveSystem()
Definition World.hpp:1333
Definition concurrentqueue.h:747
Definition World.hpp:176
Definition World.hpp:144
Definition World.hpp:139
uint32 uint32_t
Definition fwd.hpp:131
uint8 uint8_t
Definition fwd.hpp:103
Definition Animation.hpp:6
Definition Types.hpp:10
Definition World.hpp:173
Definition Entity.hpp:11
Definition World.hpp:97
Definition AudioSource.hpp:209
Definition AudioSource.hpp:192
Definition World.hpp:39
Definition World.hpp:153
Definition World.hpp:156
Definition World.hpp:148
void for_each(const func_t &f)
Definition World.hpp:552
Definition qualifier.hpp:36
Definition qualifier.hpp:35
Definition base.h:304