1 /************************************************************************************************************************
2 Most important module. Almost every function is called from EntityManager.
3 
4 Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz
5 License: BSD 3-clause, see LICENSE file in project root folder.
6 */
7 module bubel.ecs.manager;
8 
9 import std.algorithm : max;
10 import std.conv : to;
11 import std.traits;
12 
13 import bubel.ecs.system; //not ordered as forward reference bug workaround
14 import bubel.ecs.block_allocator;
15 import bubel.ecs.entity;
16 import bubel.ecs.events;
17 import bubel.ecs.hash_map;
18 import bubel.ecs.id_manager;
19 import bubel.ecs.simple_vector;
20 import bubel.ecs.std;
21 import bubel.ecs.traits;
22 import bubel.ecs.vector;
23 import bubel.ecs.atomic;
24 
25 alias SerializeVector = bubel.ecs.vector.Vector!ubyte;
26 
27 ///Global EntityManager used for everything.
28 export __gshared EntityManager* gEntityManager = null;
29 
30 /************************************************************************************************************************
31 Entity manager is responsible for everything.
32 
33 Entity manager can be in three states:
34  - registration: time between beginRegister() and endRegister() calls.
35  - update: time between being() and end() calls.
36  - default: when it's not in registration or update time
37 
38 Manager can be only in one state simultaneously.
39 
40 Manager must be initialized before use. There is global instance of EntityManager: gEntityManager or gEntityManager as alias.
41 
42 Registration process consist of registration of passes, systems, entities and events.
43 
44 Pass is group of system which should be used inside one update() call. Passes are added as name (string) and can be referenced by name or id.
45 System is structure responsible for update of specified group of entities. System consist of EntitiesData structure which contain components used
46 by system and some callback. Main callback is onUpdate() which is called by update() entity manager function. Other callbacks are used as listeners for
47 adding entites, tracking system lifetime and events handling.
48 
49 Component is basicly small fraction of data which is considered to be used as whole. In best scenario every byte of component is used when it's refered to.
50 In practice sometimes it's better to join data into one component even if it's can be accessed separetly.
51 Events are structures with data used to handle events. Event can contain for exmaple one floating point number used as damage dealt to entity.
52 Entity is group of components. In memory entity is only ID which makes it's possible to take it's components. Components are grouped into chunks, and 
53 grouped by component type so entity can be fracted in big memory chunk.
54 
55 There is two types of update:
56  - update(): function used to call update pass.
57  - updateMT(): function used to call update pass multithreaded. This call only generates jobs which must be called by user.
58 
59  WARNING! No fileds from EntityManager should be used directly, they are not private for special, advanced things which are not implemented in library.
60  So if you don't need anything special, simply use only EntityManager methods.
61 */
62 export struct EntityManager
63 {
64     /************************************************************************************************************************
65     Initialize ECS.
66     */
67     export static void initialize(uint threads_count = 1, uint page_size = 32768,
68         uint block_pages_count = 128)
69     {
70         if (gEntityManager is null)
71         {
72             gEntityManager = Mallocator.make!EntityManager(threads_count, page_size, block_pages_count);
73 
74             with (gEntityManager)
75             {
76                 UpdatePass* pass = Mallocator.make!UpdatePass;
77                 pass.name = Mallocator.makeArray(cast(char[]) "update");
78                 passes.add(pass);
79                 passes_map.add(cast(const(char)[]) pass.name, cast(ushort)(passes.length - 1));
80             }
81         }
82     }
83 
84     /************************************************************************************************************************
85     Deinitialize and destroy ECS. This function release whole memory.
86     */
87     export static void destroy() nothrow @nogc
88     {
89         if (gEntityManager is null)
90             return;
91 
92         with (gEntityManager)
93         {
94             foreach (ref system; systems)
95             {
96                 system.destroy();
97             }
98 
99             foreach (EntityInfo* info; &entities_infos.byValue)
100             {
101                 //if(info.components)Mallocator.dispose(info.components);
102 
103                 Mallocator.dispose(info);
104             }
105 
106             foreach (UpdatePass* pass; passes)
107             {
108                 Mallocator.dispose(pass);
109             }
110             passes.clear();
111 
112             foreach (ComponentInfo info; components)
113             {
114                 if (info.init_data)
115                     Mallocator.dispose(info.init_data);
116             }
117 
118             foreach (EventInfo info; events)
119             {
120                 if (info.callers)
121                     Mallocator.dispose(info.callers);
122             }
123 
124             foreach (name; &components_map.byKey)
125             {
126                 if (name)
127                     Mallocator.dispose(name);
128             }
129         }
130 
131         Mallocator.dispose(gEntityManager);
132         gEntityManager = null;
133     }
134 
135     /************************************************************************************************************************
136     Begin registering process. Every register function should be called between beginRegister() and endRegister().
137     */
138     export void beginRegister() nothrow @nogc
139     {
140         assert(!register_state, "beginRegister() can't be called twice before endRegister();");
141         register_state = true;
142 
143         foreach (pass; passes)
144         {
145             foreach (caller; pass.system_callers)
146             {
147                 Mallocator.dispose(caller);
148             }
149             pass.system_callers.clear();
150         }
151     }
152 
153     /************************************************************************************************************************
154     End registering process. Every register function should be called between beginRegister() and endRegister().
155     */
156     export void endRegister()
157     {
158         assert(register_state, "beginRegister() should be called before endRegister();");
159         register_state = false;
160 
161         foreach (ref info; &entities_infos.byValue)
162         {
163             if (info.systems)
164                 Mallocator.dispose(info.systems);
165             info.systems = Mallocator.makeArray!bool(systems.length);
166         }
167 
168         foreach (ref system; systems)
169         {
170             if (system.isAlive() == false)
171                 continue;
172             if (system.m_empty)
173             {
174                 if (system.m_update)
175                     addSystemCaller(system.id);
176                 continue;
177             }
178             if (system.m_update is null)
179             {
180                 if (system.m_add_entity || system.m_remove_entity
181                     || system.m_change_entity || system.m_event_callers.length)
182                 {
183                     foreach (info; &entities_infos.byValue)
184                     {
185                         connectListenerToEntityInfo(*info, system.id);
186                     }
187                 }
188                 continue;
189             }
190 
191             /*bool added = false;
192             foreach (i, caller; passes[system.m_pass].system_callers)
193             {
194                 if (systems[caller.system_id].priority > system.priority)
195                 {
196                     SystemCaller* sys_caller = Mallocator.make!SystemCaller;
197                     sys_caller.system_id = system.id;
198                     sys_caller.job_group.caller = sys_caller;
199                     system.m_any_system_caller = sys_caller;
200                     passes[system.m_pass].system_callers.add(sys_caller, i);
201                     added = true;
202                     break;
203                 }
204             }
205             if (!added)
206             {
207                 SystemCaller* sys_caller = Mallocator.make!SystemCaller;
208                 sys_caller.system_id = system.id;
209                 sys_caller.job_group.caller = sys_caller;
210                 system.m_any_system_caller = sys_caller;
211                 passes[system.m_pass].system_callers.add(sys_caller);
212             }*/
213             addSystemCaller(system.id);
214 
215             foreach (info; &entities_infos.byValue)
216             {
217                 addSystemCaller(*info, system.id);
218                 //info.systems[system.id] = true;
219             }
220         }
221 
222         event_manager.allocateData(cast(uint) threads.length);
223 
224         foreach (ref info; events)
225         {
226             Mallocator.dispose(info.callers);
227         }
228 
229         ushort[] event_callers = (cast(ushort*) alloca(ushort.sizeof * events.length))[0
230             .. events.length];
231         foreach (ref caller; event_callers)
232             caller = 0;
233 
234         foreach (ref system; systems)
235         {
236             if (system.isAlive() == false)
237                 continue;
238             foreach (caller; system.m_event_callers)
239             {
240                 event_callers[caller.id]++;
241             }
242         }
243 
244         foreach (i, ref info; events)
245         {
246             info.callers = Mallocator.makeArray!(EventCaller)(event_callers[i]);
247         }
248 
249         foreach (ref caller; event_callers)
250             caller = 0;
251 
252         foreach (ref system; systems)
253         {
254             if (system.isAlive() == false)
255                 continue;
256             foreach (caller; system.m_event_callers)
257             {
258                 events[caller.id].callers[event_callers[caller.id]].callback = caller.callback;
259                 events[caller.id].callers[event_callers[caller.id]].system = &system;
260                 event_callers[caller.id]++;
261             }
262         }
263 
264         extern (C) static int comapreEventCaller(const void* a, const void* b) nothrow @nogc
265         {
266             EventCaller _a = *cast(EventCaller*) a;
267             EventCaller _b = *cast(EventCaller*) b;
268             if (_a.system.priority < _b.system.priority)
269                 return -1;
270             else if (_a.system.priority == _b.system.priority)
271                 return 0;
272             else
273                 return 1;
274         }
275 
276         foreach (ref event; events)
277         {
278             qsort(event.callers.ptr, event.callers.length,
279                 EventCaller.sizeof, &comapreEventCaller);
280         }
281         //qsort(event_callers.ptr, event_callers.length, EventInfo.sizeof, &compareUShorts);
282 
283         foreach (EntityInfo* info; &entities_infos.byValue)
284         {
285             generateListeners(info);
286         }
287 
288         generateDependencies();
289     }
290 
291     /************************************************************************************************************************
292     *Default constructor.
293     */
294     export this(uint threads_count, uint page_size, uint block_pages_count) nothrow @nogc
295     {
296         if (threads_count == 0)
297             threads_count = 1;
298         threads = Mallocator.makeArray!ThreadData(threads_count);
299 
300         m_page_size = page_size;
301         m_pages_in_block = block_pages_count;
302 
303         id_manager.initialize();
304         event_manager.initialize(&this);
305 
306         allocator = BlockAllocator(m_page_size, m_pages_in_block);
307 
308         //add_mutex = Mallocator.make!Mutex;
309         entity_block_alloc_mutex = Mallocator.make!Mutex;
310         entity_block_alloc_mutex.initialize();
311         //event_manager = EventManager(this);
312         //event_manager.manager = this;
313     }
314 
315     export ~this() nothrow @nogc
316     {
317         id_manager.deinitialize();
318         event_manager.destroy();
319 
320         if (threads)
321             Mallocator.dispose(threads);
322         if (entity_block_alloc_mutex)
323         {
324             entity_block_alloc_mutex.destroy();
325             Mallocator.dispose(entity_block_alloc_mutex);
326             entity_block_alloc_mutex = null;
327         }
328 
329         allocator.freeMemory();
330     }
331 
332     /************************************************************************************************************************
333     Unregister given system form EntityManager.
334     */
335     void unregisterSystem(Sys)()
336     {
337         ushort system_id = becsID!Sys;
338         System* system = getSystem(system_id);
339 
340         unregisterSystem(system);
341     }
342 
343     /************************************************************************************************************************
344     Unregister given system form EntityManager.
345     */
346     export void unregisterSystem(System* system) nothrow @nogc
347     {
348         assert(register_state, "unregisterSystem must be called between beginRegister() and endRegister().");
349         assert(system !is null, "System was not registered");
350         assert(system.isAlive, "System already unregistered");
351         
352         //disable, destroy and dispose user created system but keep name and other data
353         system.destroySystemData();
354     }
355 
356     /************************************************************************************************************************
357     Same as "void registerSystem(Sys)(int priority, int pass = 0)" but use pass name instead of id.
358     */
359     void registerSystem(Sys)(int priority, const(char)[] pass_name)
360     {
361         ushort pass = passes_map.get(pass_name, ushort.max);
362         version (D_BetterC)
363             assert(pass != ushort.max, "Update pass doesn't exist.");
364         else
365             assert(pass != ushort.max, "Update pass (Name " ~ pass_name ~ ") doesn't exist.");
366         registerSystem!(Sys)(priority, pass);
367     }
368 
369     /************************************************************************************************************************
370     Register new System into EntityManager. This funcion generate glue between EntityManager and System.
371     Systems can be registered from external dynamic library, and can be registered after adding entities too.
372     System mustn't be registered before components which system want to use, in this case functions call assertion.
373     
374     Params:
375     priority = system priority. Priority determines order of execution of systems updates
376     pass = index of UpdatePass which sholud call system update
377     */
378     void registerSystem(Sys)(int priority, ushort pass = 0)
379     {
380         //alias STC = ParameterStorageClass;
381 
382         assert(register_state,
383             "registerSystem must be called between beginRegister() and endRegister().");
384         version (D_BetterC)
385             assert(pass < passes.length, "Update pass doesn't exist.");
386         else
387             assert(pass < passes.length, "Update pass (ID " ~ pass.to!string ~ ") doesn't exist.");
388 
389         // enum SystemName = fullyQualifiedName!Sys;
390         enum SystemName = fullName!Sys;
391         //enum SystemName = Sys.stringof;
392 
393         System system;
394         system.m_pass = pass;
395 
396         // static if (!(hasMember!(Sys, "system_id")) || !is(typeof(Sys.system_id) == ushort))
397         // {
398         //     static assert(0, "Add \"mixin ECS.System;\" in top of system structure;");
399         // }
400 
401         static if (!(hasMember!(Sys, "EntitiesData")))
402         {
403             static assert(0, "System should gave \"EntitiesData\" struct for input components");
404         }
405 
406         static if (hasMember!(Sys, "handleEvent"))
407         {
408             static void callEventHandler(Type)(ref EventCallData data)
409             {
410                 Sys* data_system = cast(Sys*) data.system_pointer;
411 
412                 Type* event = cast(Type*) data.event;
413                 data_system.handleEvent(data.entity, *event);
414             }
415 
416             void setEventCallers(Sys)(ref System system)
417             {
418                 enum event_handlers_num = __traits(getOverloads, Sys, "handleEvent").length;
419                 System.EventCaller[] callers = (cast(System.EventCaller*) alloca(
420                         event_handlers_num * System.EventCaller.sizeof))[0 .. event_handlers_num];
421                 int i = 0;
422 
423                 foreach (j, func; __traits(getOverloads, Sys, "handleEvent"))
424                 {
425                     alias Params = Parameters!(__traits(getOverloads, Sys, "handleEvent")[j]);
426                     static if (Params.length == 2 && is(Params[0] == Entity*))
427                     {
428                         alias EventParamType = Params[1];
429                         enum EventName = fullName!(Unqual!(EventParamType));
430                         // enum EventName = fullyQualifiedName!(Unqual!(EventParamType));//.stringof;
431                         ushort evt = events_map.get(cast(char[]) EventName, ushort.max);
432                         assert(evt != ushort.max,
433                             "Can't register system \"" ~ SystemName
434                                 ~ "\" due to non existing event \"" ~ EventName ~ "\".");
435 
436                         callers[i].callback = cast(void*)&callEventHandler!(EventParamType);
437                         callers[i].id = becsID!EventParamType;
438                         i++;
439                     }
440                 }
441 
442                 system.m_event_callers = Mallocator.makeArray(callers[0 .. i]);
443             }
444 
445             static if (__traits(hasMember, Sys, "handleEvent"))
446             {
447                 setEventCallers!(Sys)(system);
448             }
449         }
450 
451         static struct CompInfo
452         {
453             string name;
454             string type;
455         }
456 
457         static struct ComponentsCounts
458         {
459             //one more than should be to prevent null arrays (zero length arrays)
460             uint readonly = 1;
461             uint mutable = 1;
462             uint excluded = 1;
463             uint optional = 1;
464             uint req = 1;
465             uint readonly_dep = 1;
466             uint writable_dep = 1;
467         }
468 
469         static ComponentsCounts getComponentsCounts()
470         {
471             ComponentsCounts components_counts;
472 
473             bool checkExcludedComponentsSomething(Sys)()
474             {
475                 return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string,
476                     typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents);
477             }
478 
479             foreach (member; __traits(allMembers, Sys.EntitiesData))
480             {
481                 alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member));
482                 if (member == "length" || member == "thread_id" || member == "job_id"
483                     || is(MemberType == Entity[]) || is(MemberType == const(Entity)[]))
484                 {
485                     //continue;
486                 }
487                 else
488                 {
489                     string name;
490                     static if (isArray!MemberType)
491                     { // Workaround. This code is never called with: not an array type, but compiler prints an error
492                         // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType));//.stringof;
493                         name = fullName!(Unqual!(typeof(MemberType.init[0])));
494                     }
495 
496                     bool is_optional;
497                     bool is_read_only;
498 
499                     if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int)))
500                     {
501                         is_read_only = true;
502                     }
503 
504                     foreach (att; __traits(getAttributes, __traits(getMember,
505                             Sys.EntitiesData, member)))
506                     {
507                         if (att == "optional")
508                         {
509                             is_optional = true;
510                         }
511                         if (att == "readonly")
512                         {
513                             is_read_only = true;
514                         }
515                     }
516                     if (is_read_only)
517                     {
518                         components_counts.readonly++;
519                     }
520                     else
521                     {
522                         components_counts.mutable++;
523                     }
524                     if (is_optional)
525                     {
526                         components_counts.optional++;
527                     }
528                     else
529                     {
530                         components_counts.req++;
531                     }
532                 }
533             }
534 
535             static if (__traits(hasMember, Sys, "ExcludedComponents"))
536             {
537                 static if (is(Sys.ExcludedComponents == enum))
538                 {
539                     foreach (str; __traits(allMembers, Sys.ExcludedComponents))
540                     {
541                         components_counts.excluded++;
542                     }
543                 }
544                 else //static if (checkExcludedComponentsSomething!Sys)
545                 {
546                     foreach (str; Sys.ExcludedComponents)
547                     {
548                         components_counts.excluded++;
549                     }
550                 }
551             }
552 
553             static if (__traits(hasMember, Sys, "ReadOnlyDependencies"))
554             {
555                 foreach (str; Sys.ReadOnlyDependencies)
556                 {
557                     components_counts.readonly_dep++;
558                 }
559             }
560 
561             static if (__traits(hasMember, Sys, "WritableDependencies"))
562             {
563                 foreach (str; Sys.WritableDependencies)
564                 {
565                     components_counts.writable_dep++;
566                 }
567             }
568 
569             return components_counts;
570         }
571 
572         enum ComponentsCounts component_counts = getComponentsCounts();
573 
574         static struct ComponentsIndices(ComponentsCounts counts)
575         {
576             CompInfo[] readonly()
577             {
578                 return m_readonly[0 .. m_readonly_counter];
579             }
580 
581             CompInfo[] mutable()
582             {
583                 return m_mutable[0 .. m_mutable_counter];
584             }
585 
586             CompInfo[] excluded()
587             {
588                 return m_excluded[0 .. m_excluded_counter];
589             }
590 
591             CompInfo[] optional()
592             {
593                 return m_optional[0 .. m_optional_counter];
594             }
595 
596             CompInfo[] req()
597             {
598                 return m_req[0 .. m_req_counter];
599             }
600 
601             CompInfo[] readonlyDeps()
602             {
603                 return m_readonly_dep[0 .. m_readonly_dep_counter];
604             }
605 
606             CompInfo[] writableDeps()
607             {
608                 return m_writable_dep[0 .. m_writable_dep_counter];
609             }
610 
611             void addReadonly(CompInfo info)
612             {
613                 m_readonly[m_readonly_counter++] = info;
614             }
615 
616             void addMutable(CompInfo info)
617             {
618                 m_mutable[m_mutable_counter++] = info;
619             }
620 
621             void addExcluded(CompInfo info)
622             {
623                 m_excluded[m_excluded_counter++] = info;
624             }
625 
626             void addOptional(CompInfo info)
627             {
628                 m_optional[m_optional_counter++] = info;
629             }
630 
631             void addReq(CompInfo info)
632             {
633                 m_req[m_req_counter++] = info;
634             }
635 
636             void addReadonlyDep(CompInfo info)
637             {
638                 m_readonly_dep[m_readonly_dep_counter++] = info;
639             }
640 
641             void addWritableDep(CompInfo info)
642             {
643                 m_writable_dep[m_writable_dep_counter++] = info;
644             }
645 
646             CompInfo[counts.readonly] m_readonly;
647             CompInfo[counts.mutable] m_mutable;
648             CompInfo[counts.excluded] m_excluded;
649             CompInfo[counts.optional] m_optional;
650             CompInfo[counts.req] m_req;
651             CompInfo[counts.readonly_dep] m_readonly_dep;
652             CompInfo[counts.writable_dep] m_writable_dep;
653 
654             uint m_readonly_counter;
655             uint m_mutable_counter;
656             uint m_excluded_counter;
657             uint m_optional_counter;
658             uint m_req_counter;
659             uint m_readonly_dep_counter;
660             uint m_writable_dep_counter;
661 
662             string entites_array;
663         }
664 
665         static void allocateSystemComponents(ComponentsIndices!component_counts components_info)(
666             ref System system)
667         {
668             size_t req = components_info.req.length;
669             size_t opt = components_info.optional.length;
670             size_t excluded = components_info.excluded.length;
671             size_t read_only = components_info.readonly.length;
672             size_t writable = components_info.mutable.length;
673             size_t read_only_deps = components_info.readonlyDeps.length;
674             size_t writable_deps = components_info.writableDeps.length;
675 
676             if (req > 0)
677                 system.m_components = Mallocator.makeArray!ushort(req);
678             if (opt > 0)
679                 system.m_optional_components = Mallocator.makeArray!ushort(opt);
680             if (excluded > 0)
681                 system.m_excluded_components = Mallocator.makeArray!ushort(excluded);
682             if (read_only > 0)
683                 system.m_read_only_components = Mallocator.makeArray!ushort(read_only);
684             if (writable > 0)
685                 system.m_writable_components = Mallocator.makeArray!ushort(writable);
686             if (read_only_deps > 0)
687                 system.m_readonly_dependencies = Mallocator.makeArray!ushort(read_only_deps);
688             if (writable_deps > 0)
689                 system.m_writable_dependencies = Mallocator.makeArray!ushort(writable_deps);
690 
691         }
692 
693         static ComponentsIndices!component_counts getComponentsInfo()
694         {
695             ComponentsIndices!component_counts components_info;
696 
697             bool checkExcludedComponentsSomething(Sys)()
698             {
699                 return __traits(compiles, allSameType!(string, typeof(Sys.ExcludedComponents))) && allSameType!(string,
700                     typeof(Sys.ExcludedComponents)) && isExpressions!(Sys.ExcludedComponents);
701             }
702 
703             foreach (member; __traits(allMembers, Sys.EntitiesData))
704             {
705                 alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member));
706                 if (member == "length" || member == "thread_id" || member == "job_id"
707                     || is(MemberType == Entity[]) || is(MemberType == const(Entity)[]))
708                 {
709                     if (is(MemberType == Entity[]) || is(MemberType == const(Entity)[]))
710                         components_info.entites_array = member;
711                     //continue;
712                 }
713                 else
714                 {
715                     string name;
716                     static if (isArray!MemberType)
717                     { // Workaround. This code is never called with: not an array type, but compiler prints an error
718                         // name = fullyQualifiedName!(Unqual!(ForeachType!MemberType));
719                         name = fullName!(Unqual!(typeof(MemberType.init[0])));
720                         //name = Unqual!(ForeachType!MemberType).stringof;
721                     }
722 
723                     bool is_optional;
724                     bool is_read_only;
725 
726                     if (is(CopyConstness!(ForeachType!(MemberType), int) == const(int)))
727                     {
728                         is_read_only = true;
729                     }
730 
731                     foreach (att; __traits(getAttributes, __traits(getMember,
732                             Sys.EntitiesData, member)))
733                     {
734                         if (att == "optional")
735                         {
736                             is_optional = true;
737                         }
738                         if (att == "readonly")
739                         {
740                             is_read_only = true;
741                         }
742                     }
743                     if (is_read_only)
744                     {
745                         components_info.addReadonly(CompInfo(member, name));
746                     }
747                     else
748                     {
749                         components_info.addMutable(CompInfo(member, name));
750                     }
751                     if (is_optional)
752                     {
753                         components_info.addOptional(CompInfo(member, name));
754                     }
755                     else
756                     {
757                         components_info.addReq(CompInfo(member, name));
758                     }
759                 }
760             }
761 
762             static if (__traits(hasMember, Sys, "ExcludedComponents"))
763             {
764                 static if (is(Sys.ExcludedComponents == enum))
765                 {
766                     foreach (str; __traits(allMembers, Sys.ExcludedComponents))
767                     {
768                         components_info.addExcluded(CompInfo(str, str));
769                     }
770                 }
771                 else //static if (checkExcludedComponentsSomething!Sys)
772                 {
773                     foreach (str; Sys.ExcludedComponents)
774                     {
775                         components_info.addExcluded(CompInfo(str.stringof, fullName!str));
776                         // components_info.addExcluded(CompInfo(str.stringof, str.stringof));
777                     }
778 
779                 }
780             }
781 
782             static if (__traits(hasMember, Sys, "ReadOnlyDependencies"))
783             {
784                 foreach (str; Sys.ReadOnlyDependencies)
785                 {
786                     components_info.addReadonlyDep(CompInfo(str, str));
787                 }
788             }
789 
790             static if (__traits(hasMember, Sys, "WritableDependencies"))
791             {
792                 foreach (str; Sys.WritableDependencies)
793                 {
794                     components_info.addWritableDep(CompInfo(str, str));
795                 }
796             }
797 
798             return components_info;
799         }
800 
801         enum ComponentsIndices!component_counts components_info = getComponentsInfo();
802 
803         static void genCompList(ref System system, ref HashMap!(char[], ushort) components_map)
804         {
805 
806             foreach (member; __traits(allMembers, Sys.EntitiesData))
807             {
808                 alias MemberType = typeof(__traits(getMember, Sys.EntitiesData, member));
809 
810                 static if (isFunction!(__traits(getMember, Sys.EntitiesData, member)))
811                     static assert(0, "EntitiesData can't have any function!");
812                 else static if (member == "length")
813                 {
814                     static assert(isIntegral!(MemberType),
815                         "EntitiesData 'length' member must be integral type.");
816                     static assert(MemberType.sizeof > 1,
817                         "EntitiesData 'length' member can't be byte or ubyte.");
818                 }
819                 else static if (member == "thread_id")
820                 {
821                     static assert(isIntegral!(MemberType),
822                         "EntitiesData 'thread_id' member must be integral type.");
823                     static assert(MemberType.sizeof > 1,
824                         "EntitiesData 'thread_id' member can't be byte or ubyte.");
825                 }
826                 else static if (member == "job_id")
827                 {
828                     static assert(isIntegral!(MemberType),
829                         "EntitiesData 'job_id' member must be integral type.");
830                     static assert(MemberType.sizeof > 1,
831                         "EntitiesData 'job_id' member can't be byte or ubyte.");
832                 }
833                 else static if (!(isArray!(MemberType)))
834                     static assert(0, "EntitiesData members should be arrays of elements!");
835             }
836 
837             //enum ComponentsIndices components_info = getComponentsInfo();
838             allocateSystemComponents!(components_info)(system);
839 
840             foreach (iii, comp_info; components_info.req)
841             {
842                 ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max);
843                 version (D_BetterC)
844                     assert(comp != ushort.max,
845                         "Can't register system \"" ~ SystemName
846                             ~ "\" due to non existing component.");
847                 else
848                     assert(comp != ushort.max, "Can't register system \"" ~ SystemName
849                             ~ "\" due to non existing component \"" ~ comp_info.type ~ "\".");
850                 system.m_components[iii] = comp;
851             }
852             foreach (iii, comp_info; components_info.excluded)
853             {
854                 ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max);
855                 version (D_BetterC)
856                     assert(comp != ushort.max,
857                         "Can't register system \"" ~ SystemName
858                             ~ "\" due to non existing component.");
859                 else
860                     assert(comp != ushort.max, "Can't register system \"" ~ SystemName
861                             ~ "\" due to non existing component \"" ~ comp_info.type ~ "\".");
862                 system.m_excluded_components[iii] = comp;
863             }
864             foreach (iii, comp_info; components_info.optional)
865             {
866                 ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max);
867                 version (D_BetterC)
868                     assert(comp != ushort.max,
869                         "Can't register system \"" ~ SystemName
870                             ~ "\" due to non existing component.");
871                 else
872                     assert(comp != ushort.max, "Can't register system \"" ~ SystemName
873                             ~ "\" due to non existing component \"" ~ comp_info.type ~ "\".");
874                 system.m_optional_components[iii] = comp;
875             }
876             foreach (iii, comp_info; components_info.readonly)
877             {
878                 ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max);
879                 version (D_BetterC)
880                     assert(comp != ushort.max,
881                         "Can't register system \"" ~ SystemName
882                             ~ "\" due to non existing component.");
883                 else
884                     assert(comp != ushort.max, "Can't register system \"" ~ SystemName
885                             ~ "\" due to non existing component \"" ~ comp_info.type ~ "\".");
886                 system.m_read_only_components[iii] = comp;
887             }
888             foreach (iii, comp_info; components_info.mutable)
889             {
890                 ushort comp = components_map.get(cast(char[]) comp_info.type, ushort.max);
891                 version (D_BetterC)
892                     assert(comp != ushort.max,
893                         "Can't register system \"" ~ SystemName
894                             ~ "\" due to non existing component.");
895                 else
896                     assert(comp != ushort.max, "Can't register system \"" ~ SystemName
897                             ~ "\" due to non existing component \"" ~ comp_info.type ~ "\".");
898                 system.m_writable_components[iii] = comp;
899             }
900         }
901 
902         static void fillInputData(ref Sys.EntitiesData input_data, EntityInfo* info,
903             EntitiesBlock* block, uint offset, uint entities_count, System* system)
904         {
905             //enum ComponentsIndices components_info = getComponentsInfo();
906 
907             static if (components_info.entites_array)
908             {
909                 __traits(getMember, input_data, components_info.entites_array) = (
910                     cast(Entity*) block.dataBegin())[offset .. entities_count];
911             }
912 
913             static if (hasMember!(Sys.EntitiesData, "length"))
914             {
915                 input_data.length = cast(typeof(input_data.length))(entities_count - offset);
916             }
917 
918             /*static if (hasMember!(Sys.EntitiesData, "thread_id"))
919             {
920                 input_data.thread_id = cast(typeof(input_data.thread_id))threadID();
921             }//*/
922 
923             ///FIXME: should be "components_info.req()" but it's not compile with GCC
924             static foreach (iii, comp_info; components_info.m_req[0
925                     .. components_info.m_req_counter])
926             {
927                 __traits(getMember, input_data, comp_info.name) = (
928                     cast(typeof(
929                         (typeof(__traits(getMember, Sys.EntitiesData, comp_info.name))).init[0]
930                     )*)(cast(void*) block + info.deltas[system.m_components[iii]])
931                 )[offset .. entities_count];
932             }
933 
934             static foreach (iii, comp_info; components_info.m_optional[0
935                     .. components_info.m_optional_counter])
936             {
937                 if (system.m_optional_components[iii] < info.deltas.length
938                     && info.deltas[system.m_optional_components[iii]] != 0)
939                 {
940                     __traits(getMember, input_data, comp_info.name) = (cast(ForeachType!(typeof(__traits(getMember,
941                             Sys.EntitiesData, comp_info.name)))*)(cast(
942                             void*) block + info.deltas[system.m_optional_components[iii]]))[offset
943                         .. entities_count];
944 
945                 }
946             }
947         }
948 
949         /*bool checkOnUpdateParams()
950         {
951             bool ret = false;
952             foreach (func; __traits(getOverloads, Sys, "onUpdate"))
953             {
954                 if ((Parameters!(func)).length == 1 && is(Parameters!(func)[0] == Sys.EntitiesData))
955                 {
956                     ret = true;
957                     break;
958                 }
959             }
960             return ret;
961         }*/
962 
963         int getOnUpdateOverload()()
964         {
965             int ret = -1;
966             foreach (i, func; __traits(getOverloads, Sys, "onUpdate"))
967             {
968                 if ((Parameters!(func)).length == 1 && is(Parameters!(func)[0] == Sys.EntitiesData))
969                 {
970                     ret = i;
971                     break;
972                 }
973             }
974             return ret;
975         }
976 
977         static if (hasMember!(Sys, "onUpdate"))
978             enum OnUpdateOverloadNum = getOnUpdateOverload();
979         else
980             enum OnUpdateOverloadNum = -1;
981         //enum HasOnUpdate = (hasMember!(Sys, "onUpdate") && checkOnUpdateParams());
982         enum IsEmpty = components_info.req.length == 0 && components_info.optional.length == 0
983             && components_info.excluded.length == 0 && components_info.entites_array.length == 0;
984 
985         static if (IsEmpty)
986             system.m_empty = true;
987 
988         static if (OnUpdateOverloadNum != -1)
989         {
990             static if (!IsEmpty)
991             {
992                 static void callUpdate(ref CallData data)
993                 {
994                     Sys* s = cast(Sys*) data.system.m_system_pointer;
995 
996                     Sys.EntitiesData input_data;
997                     EntityInfo* info = data.info; //block.type_info;
998                     System* system = data.system;
999 
1000                     EntitiesBlock* block;
1001                     if (data.first_block)
1002                         block = data.first_block;
1003                     else
1004                         block = info.first_block;
1005 
1006                     uint offset = data.begin;
1007                     uint entities_count;
1008                     uint blocks;
1009                     if (data.blocks)
1010                         blocks = data.blocks;
1011                     else
1012                         blocks = uint.max;
1013 
1014                     while (block !is null && blocks > 0)
1015                     {
1016                         if (blocks == 1)
1017                         {
1018                             if (data.end)
1019                                 entities_count = data.end;
1020                             else
1021                                 entities_count = block.entities_count;
1022                         }
1023                         else
1024                             entities_count = block.entities_count;
1025 
1026                         if (entities_count > 0)
1027                         {
1028                             assert(entities_count <= block.entities_count
1029                                     && offset < block.entities_count);
1030                             assert(entities_count > offset);
1031 
1032                             fillInputData(input_data, info, block, offset, entities_count, system);
1033 
1034                             static if (hasMember!(Sys.EntitiesData, "thread_id"))
1035                             {
1036                                 input_data.thread_id = cast(
1037                                     typeof(input_data.thread_id)) data.thread_id;
1038                             }
1039 
1040                             static if (hasMember!(Sys.EntitiesData, "job_id"))
1041                             {
1042                                 input_data.job_id = cast(typeof(input_data.job_id)) data.job_id;
1043                             }
1044 
1045                             //s.onUpdate(input_data);
1046                             (cast(typeof(&__traits(getOverloads, s,
1047                                     "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(
1048                                 input_data);
1049                         }
1050                         block = block.next_block;
1051                         offset = 0;
1052                         blocks--;
1053                     }
1054                 }
1055             }
1056             else
1057             {
1058                 static void callUpdate(ref CallData data)
1059                 {
1060                     Sys* s = cast(Sys*) data.system.m_system_pointer;
1061 
1062                     Sys.EntitiesData input_data;
1063 
1064                     /*static if (hasMember!(Sys.EntitiesData, "length"))
1065                     {
1066                         input_data.length = 0;
1067                     }//*/
1068 
1069                     static if (hasMember!(Sys.EntitiesData, "thread_id"))
1070                     {
1071                         input_data.thread_id = cast(typeof(input_data.thread_id)) data.thread_id;
1072                     }
1073 
1074                     static if (hasMember!(Sys.EntitiesData, "job_id"))
1075                     {
1076                         input_data.job_id = cast(typeof(input_data.job_id)) data.job_id;
1077                     }
1078 
1079                     (cast(typeof(&__traits(getOverloads, s,
1080                             "onUpdate")[OnUpdateOverloadNum])) data.update_delegate)(input_data);
1081                 }
1082             }
1083 
1084             system.m_update = &callUpdate;
1085         }
1086 
1087         static void catchFunction(string func_name, RetType = void)(void** member)
1088         {
1089             static if (hasMember!(Sys, func_name))
1090             {
1091                 foreach (func; __traits(getOverloads, Sys, func_name))
1092                 {
1093                     static if ((Parameters!(func)).length == 0 && is(ReturnType!(func) == RetType))
1094                     {
1095                         static RetType callFunc(void* system_pointer)
1096                         {
1097                             Sys* s = cast(Sys*) system_pointer;
1098                             static if (is(RetTyp == void))
1099                                 mixin("s." ~ func_name ~ "()");
1100                             else
1101                                 return mixin("s." ~ func_name ~ "()");
1102                         }
1103 
1104                         *member = cast(void*)&callFunc;
1105                         break;
1106                     }
1107                 }
1108             }
1109         }
1110 
1111         static void catchEntityFunction(string func_name, RetType = void)(void** member)
1112         {
1113             static if (hasMember!(Sys, func_name))
1114             {
1115                 foreach (func; __traits(getOverloads, Sys, func_name))
1116                 {
1117                     static if ((Parameters!(func)).length == 1
1118                         && is(Parameters!(func)[0] == Sys.EntitiesData)
1119                         && is(ReturnType!(func) == RetType))
1120                     {
1121                         static RetType callFunc(ref ListenerCallData data)
1122                         {
1123                             Sys* s = cast(Sys*) data.system.m_system_pointer;
1124                             Sys.EntitiesData input_data;
1125                             fillInputData(input_data, data.block.type_info,
1126                                 data.block, data.begin, data.end, data.system);
1127                             static if (is(RetTyp == void))
1128                                 mixin("s." ~ func_name ~ "(input_data)");
1129                             else
1130                                 return mixin("s." ~ func_name ~ "(input_data)");
1131                         }
1132 
1133                         *member = cast(void*)&callFunc;
1134                         break;
1135                     }
1136                 }
1137             }
1138         }
1139 
1140         static void catchEntityFilterFunction(string func_name, RetType = void)(void** member)
1141         {
1142             static if (hasMember!(Sys, func_name))
1143             {
1144                 foreach (func; __traits(getOverloads, Sys, func_name))
1145                 {
1146                     static if ((Parameters!(func)).length == 1
1147                         && is(Parameters!(func)[0] == EntityInfo*)
1148                         && is(ReturnType!(func) == RetType))
1149                     {
1150                         static RetType callFunc(void* system_pointer, EntityInfo* info)
1151                         {
1152                             Sys* s = cast(Sys*) system_pointer;
1153                             static if (is(RetTyp == void))
1154                                 mixin("s." ~ func_name ~ "(info)");
1155                             else
1156                                 return mixin("s." ~ func_name ~ "(info)");
1157                         }
1158 
1159                         *member = cast(void*)&callFunc;
1160                         break;
1161                     }
1162                 }
1163             }
1164         }
1165 
1166         catchFunction!("onEnable")(&system.m_enable);
1167         catchFunction!("onDisable")(&system.m_disable);
1168         catchFunction!("onCreate")(&system.m_create);
1169         catchFunction!("onDestroy")(&system.m_destroy);
1170         catchFunction!("onBegin", bool)(&system.m_begin);
1171         catchFunction!("onEnd")(&system.m_end);
1172 
1173         catchEntityFunction!("onAddEntity")(&system.m_add_entity);
1174         catchEntityFunction!("onRemoveEntity")(&system.m_remove_entity);
1175         catchEntityFunction!("onChangeEntity")(&system.m_change_entity);
1176 
1177         catchEntityFilterFunction!("filterEntity", bool)(&system.m_filter_entity);
1178 
1179         system.m_system_pointer = cast(void*) Mallocator.make!Sys;
1180         system.m_priority = priority;
1181         //(cast(Sys*) system.m_system_pointer).__ecsInitialize();
1182         //system.jobs =  (cast(Sys*) system.m_system_pointer)._ecs_jobs;
1183         static if (__traits(hasMember, Sys, "__becs_jobs_count"))
1184             system.jobs = Mallocator.makeArray!(Job)(Sys.__becs_jobs_count);
1185         else
1186             system.jobs = Mallocator.makeArray!(Job)(32);
1187 
1188         static if (OnUpdateOverloadNum != -1)
1189         {
1190             Sys* s = cast(Sys*) system.m_system_pointer;
1191             system.m_update_delegate = cast(void delegate())&__traits(getOverloads,
1192                 s, "onUpdate")[OnUpdateOverloadNum];
1193         }
1194 
1195         genCompList(system, components_map);
1196 
1197         foreach (iii, comp_info; components_info.readonlyDeps)
1198         {
1199             ushort comp = external_dependencies_map.get(cast(const(char)[]) comp_info.type,
1200                 ushort.max);
1201             version (D_BetterC)
1202                 assert(comp != ushort.max,
1203                     "Can't register system \"" ~ SystemName
1204                         ~ "\" due to non existing dependency.");
1205             else
1206                 assert(comp != ushort.max, "Can't register system \"" ~ SystemName
1207                         ~ "\" due to non existing dependency \"" ~ comp_info.type ~ "\".");
1208             system.m_readonly_dependencies[iii] = comp;
1209         }
1210 
1211         foreach (iii, comp_info; components_info.writableDeps)
1212         {
1213             ushort comp = external_dependencies_map.get(cast(char[]) comp_info.type, ushort.max);
1214             version (D_BetterC)
1215                 assert(comp != ushort.max,
1216                     "Can't register system \"" ~ SystemName
1217                         ~ "\" due to non existing dependency.");
1218             else
1219                 assert(comp != ushort.max, "Can't register system \"" ~ SystemName
1220                         ~ "\" due to non existing dependency \"" ~ comp_info.type ~ "\".");
1221             system.m_writable_dependencies[iii] = comp;
1222         }
1223 
1224         ushort sys_id = systems_map.get(cast(char[]) SystemName, ushort.max);
1225         if (sys_id < systems.length)
1226         {
1227             system.m_name = systems[sys_id].m_name;
1228             systems[sys_id].m_name = null;
1229             systems[sys_id].destroy();
1230 
1231             if (system.m_create)
1232                 (cast(void function(void*)) system.m_create)(system.m_system_pointer);
1233 
1234             system.enable();
1235 
1236             system.m_id = sys_id;
1237             systems[sys_id] = system;
1238         }
1239         else
1240         {
1241             system.m_name = Mallocator.makeArray(cast(char[]) SystemName);
1242 
1243             systems_map.add(system.m_name, cast(ushort) systems.length);
1244 
1245             system.m_id = cast(ushort)(systems.length);
1246 
1247             systems.add(system);
1248 
1249             if (system.m_create)
1250                 (cast(void function(void*)) system.m_create)(system.m_system_pointer);
1251 
1252             systems[$ - 1].enable();
1253         }
1254         becsID!Sys = system.id;
1255     }
1256 
1257     /************************************************************************************************************************
1258     Return system ECS api by id.
1259     System pointer might become invalid after registration process. It should be get once again after new systems are registered.
1260     */
1261     export System* getSystem(ushort id) nothrow @nogc
1262     {
1263         if (id >= systems.length)
1264             return null;
1265         return &systems[id];
1266     }
1267 
1268     /************************************************************************************************************************
1269     Return pointer to system registered in manager
1270     */
1271     Sys* getSystem(Sys)() nothrow @nogc
1272     {
1273         if (becsID!Sys >= systems.length)
1274             return null;
1275         return cast(Sys*) systems[becsID!Sys].m_system_pointer;
1276     }
1277 
1278     export ushort registerPass(const(char)[] name)
1279     {
1280         UpdatePass* pass = Mallocator.make!UpdatePass;
1281         pass.name = Mallocator.makeArray(cast(char[]) name);
1282         passes.add(pass);
1283         passes_map.add(name, cast(ushort)(passes.length - 1));
1284         return cast(ushort)(passes.length - 1);
1285     }
1286 
1287     export void registerDependency(const(char)[] name)
1288     {
1289         return external_dependencies_map.add(name, cast(ushort) external_dependencies_map.length);
1290     }
1291 
1292     /************************************************************************************************************************
1293     Register component into EntityManager.
1294     */
1295     void registerComponent(Comp)()
1296     {
1297         ComponentInfo info;
1298 
1299         // enum ComponentName = fullyQualifiedName!Comp;
1300         enum ComponentName = fullName!Comp;
1301         // enum ComponentName = Comp.stringof;
1302 
1303         // static if (!(hasMember!(Comp, "component_id")) || !is(typeof(Comp.component_id) == ushort))
1304         // {
1305         //     static assert(0, "Add \"mixin ECS.Component;\" in top of component structure;");
1306         // }
1307 
1308         static if (hasMember!(Comp, "onDestroy") && isFunction!(Comp.onDestroy)
1309             && is(ReturnType!(Comp.onDestroy) == void)
1310             && Parameters!(Comp.onDestroy).length == 0)
1311         {
1312             static void callDestroy(void* pointer) nothrow @nogc
1313             {
1314                 (cast(void delegate() nothrow @nogc)&(cast(Comp*) pointer).onDestroy)();
1315             }
1316 
1317             info.destroy_callback = &callDestroy;
1318         }
1319 
1320         static if (hasMember!(Comp, "onCreate") && isFunction!(Comp.onCreate)
1321             && is(ReturnType!(Comp.onCreate) == void) && Parameters!(Comp.onCreate).length == 0)
1322         {
1323             static void callCreate(void* pointer) nothrow @nogc
1324             {
1325                 (cast(void delegate() nothrow @nogc)&(cast(Comp*) pointer).onCreate)();
1326             }
1327 
1328             info.create_callback = &callCreate;
1329         }
1330 
1331         static if (Comp.sizeof == 1 && Fields!(Comp).length == 0)
1332             info.size = 0;
1333         else
1334             info.size = Comp.sizeof;
1335         info.alignment = Comp.alignof; //8;
1336         info.init_data = Mallocator.makeArray!ubyte(Comp.sizeof);
1337         __gshared Comp init_memory;
1338         memcpy(info.init_data.ptr, &init_memory, Comp.sizeof);
1339 
1340         ushort comp_id = components_map.get(cast(char[]) ComponentName, ushort.max);
1341         if (comp_id < components.length)
1342         {
1343             becsID!Comp = comp_id;
1344             if (components[comp_id].init_data)
1345                 Mallocator.dispose(components[comp_id].init_data);
1346             components[comp_id] = info;
1347         }
1348         else
1349         {
1350             components.add(info);
1351             becsID!Comp = cast(ushort)(components.length - 1);
1352             char[] name = Mallocator.makeArray(cast(char[]) ComponentName);
1353             components_map.add(name, cast(ushort)(components.length - 1));
1354         }
1355     }
1356 
1357     void registerEvent(Ev)()
1358     {
1359         EventInfo info;
1360 
1361         // static if (!(hasMember!(Ev, "event_id")) || !is(typeof(Ev.event_id) == ushort))
1362         // {
1363         //     static assert(0, "Add \"mixin ECS.Event;\" in top of event structure;");
1364         // }
1365 
1366         static if (hasMember!(Ev, "onDestroy") && isFunction!(Ev.onDestroy)
1367             && is(ReturnType!(Ev.onDestroy) == void) && Parameters!(Ev.onDestroy).length == 0)
1368         {
1369             static void callDestroy(void* pointer)
1370             {
1371                 (cast(Ev*) pointer).onDestroy();
1372             }
1373 
1374             info.destroy_callback = cast(void function(void*) nothrow @nogc)&callDestroy;
1375         }
1376 
1377         info.size = Ev.sizeof;
1378         info.alignment = Ev.alignof;
1379 
1380         //ushort event_id = events_map.get(Ev.stringof, ushort.max);
1381         ushort event_id = events_map.get(fullName!Ev, ushort.max);
1382         if (event_id < events.length)
1383         {
1384             becsID!Ev = event_id;
1385         }
1386         else
1387         {
1388             events.add(info);
1389             becsID!Ev = cast(ushort)(events.length - 1);
1390             // events_map.add(Ev.stringof, cast(ushort)(events.length - 1));
1391             events_map.add(fullName!Ev, cast(ushort)(events.length - 1));
1392         }
1393     }
1394 
1395     export void callEntitiesFunction(Sys, T)(T func)
1396     {
1397         //TODO: check if onUpdate function is good
1398         Sys* s;
1399         static assert(isDelegate!func, "Function must be delegate.");
1400         static assert(__traits(hasMember, Sys, "EntitiesData"),
1401             "Can't call function with system which hasn't EntitesData structure.");
1402         ///TODO: make possibly to call function to group without system with onUpdate function
1403         static assert(__traits(hasMember, Sys, "onUpdate"),
1404             "Can't call function with system which hasn't onUpdate function callback.");
1405         // static assert(is(SetFunctionAttributes!(T, functionLinkage!(s.onUpdate),
1406         //         functionAttributes!(s.onUpdate)) == typeof(&s.onUpdate)),
1407         //         "Function must match system update function."); FIXME: It's lead to crash on android build
1408         // static assert(__traits(hasMember, Sys, "system_id"), "Sys must be system type.");
1409 
1410         System* system = getSystem(becsID!Sys);
1411         assert(system != null,
1412             "System must be registered in EntityManager before any funcion can be called.");
1413         assert(system.isAlive(), "System must be alive (registered) in order to call entities function on its entities");
1414 
1415         if (!system.m_any_system_caller)
1416             return;
1417 
1418         foreach (info; system.m_any_system_caller.infos)
1419         {
1420             CallData data = CallData(system.id, system, info, cast(void delegate()) func);
1421             data.update();
1422         }
1423     }
1424 
1425     /************************************************************************************************************************
1426     Same as "void update(int pass = 0)" but use pass name instead of id.
1427     */
1428     export void update(const(char)[] pass_name) nothrow @nogc
1429     {
1430         ushort pass = passes_map.get(pass_name, ushort.max);
1431         assert(pass != ushort.max);
1432         update(pass);
1433     }
1434 
1435     /************************************************************************************************************************
1436     Update systems. Should be called only between begin() and end().
1437     */
1438     export void update(ushort pass = 0) nothrow @nogc
1439     {
1440         assert(!register_state);
1441         assert(pass < passes.length);
1442         foreach (caller; passes[pass].system_callers)
1443         {
1444             System* sys = &systems[caller.system_id];
1445             if (sys.enabled && sys.willExecute)
1446             {
1447                 if (sys.m_empty)
1448                 {
1449                     CallData data = CallData(caller.system_id, sys, null, sys.m_update_delegate);
1450                     data.update();
1451                 }
1452                 else
1453                     foreach (info; caller.infos)
1454                     {
1455                         CallData data = CallData(caller.system_id, sys, info,
1456                             sys.m_update_delegate);
1457                         data.update();
1458                     }
1459             }
1460         }
1461     }
1462 
1463     /************************************************************************************************************************
1464     Same as "void updateMT(int pass = 0)" but use pass name instead of id.
1465     */
1466     export void updateMT(const(char)[] pass_name) nothrow @nogc
1467     {
1468         ushort pass = passes_map.get(pass_name, ushort.max);
1469         assert(pass != ushort.max);
1470         updateMT(pass);
1471     }
1472 
1473     export void updateMT(ushort pass = 0) nothrow @nogc
1474     {
1475         assert(!register_state);
1476         assert(pass < passes.length);
1477         assert(m_dispatch_jobs,
1478             "Can't update with multithreading without JobDispatch function. Please use setJobDispatchFunc().");
1479         Vector!CallData tmp_datas;
1480         tmp_datas.reserve(8);
1481 
1482         foreach (caller; passes[pass].system_callers)
1483         {
1484             System* sys = &systems[caller.system_id];
1485             if (sys.enabled && sys.willExecute)
1486             {
1487                 uint job_id = 0;
1488                 void nextJob()
1489                 {
1490                     CallData[] callers = m_call_data_allocator.getCallData(
1491                         cast(uint) tmp_datas.length);
1492                     //callers[0 .. $] = tmp_datas[0 .. $];
1493                     memcpy(callers.ptr, &tmp_datas[0], CallData.sizeof * tmp_datas.length);
1494                     tmp_datas.clear();
1495                     sys.jobs[job_id].callers = callers;
1496                     sys.jobs[job_id].id = job_id;
1497                     job_id++;
1498                 }
1499 
1500                 if (sys.m_empty)
1501                 {
1502                     tmp_datas.add(CallData(caller.system_id, sys, null, sys.m_update_delegate));
1503                     nextJob();
1504                     caller.job_group.jobs = sys.jobs[0 .. 1];
1505                     (cast(void delegate(JobGroup) nothrow @nogc) m_dispatch_jobs)(caller.job_group);
1506                     continue;
1507                 }
1508                 uint entities_count = 0;
1509                 foreach (info; caller.infos)
1510                 {
1511                     uint blocks_count = info.nonEmptyBlocksCount();
1512                     if (blocks_count == 0)
1513                         continue;
1514                     if (blocks_count > 1)
1515                         entities_count += (blocks_count - 1) * info.max_entities;
1516                     entities_count += info.last_block.entities_count;
1517                 }
1518 
1519                 if (!entities_count)
1520                     continue;
1521 
1522                 uint jobs_count = cast(uint) sys.jobs.length;
1523                 uint entities_per_job = entities_count / jobs_count + 1;
1524 
1525                 if (entities_per_job <= 4)
1526                 {
1527                     jobs_count = entities_count / 4;
1528                     if (jobs_count == 0)
1529                         jobs_count = 1;
1530                     entities_per_job = entities_count / jobs_count + 1;
1531                 }
1532 
1533                 entities_count = 0;
1534 
1535                 foreach (info; caller.infos)
1536                 {
1537                     uint blocks_count = info.nonEmptyBlocksCount();
1538                     EntitiesBlock* first_block = info.first_block;
1539                     uint first_elem = 0;
1540                 begin:
1541                     if (first_block is null || blocks_count == 0)
1542                         continue;
1543 
1544                     //if this info will fill job
1545                     if ((blocks_count - 1) * info.max_entities + entities_count
1546                         + info.last_block.entities_count - first_elem >= entities_per_job)
1547                     {
1548                         int reamaining_entities = (entities_per_job - entities_count - (
1549                                 first_block.entities_count - first_elem));
1550 
1551                         //if first block don't fill job
1552                         if (reamaining_entities > 0)
1553                         {
1554                             //take as many full blocks as possible
1555                             int full_blocks_count = reamaining_entities / info.max_entities;
1556                             EntitiesBlock* block = first_block;
1557                             foreach (i; 0 .. full_blocks_count + 1)
1558                                 block = block.next_block;
1559 
1560                             //if full block + actual contained entities + remaining entities form first block > entities count per job
1561                             if (full_blocks_count * info.max_entities + entities_count + (
1562                                     first_block.entities_count - first_elem) >= entities_per_job)
1563                             {
1564                                 assert(entities_per_job == full_blocks_count * info.max_entities + entities_count + (
1565                                         first_block.entities_count - first_elem));
1566                                 CallData data = CallData(caller.system_id, sys,
1567                                     info, sys.m_update_delegate, first_block,
1568                                     cast(ushort)(full_blocks_count + 1),
1569                                     cast(ushort) first_elem, 0);
1570                                 tmp_datas.add(data);
1571                                 first_elem = 0;
1572                                 blocks_count -= full_blocks_count + 1;
1573                                 first_block = block;
1574                             }
1575                             else
1576                             {
1577                                 entities_count += full_blocks_count * info.max_entities + (
1578                                     first_block.entities_count - first_elem); // - first_elem;
1579                                 uint last_elem = entities_per_job - entities_count; // + first_elem - 1;
1580                                 assert(last_elem > 0);
1581                                 assert(last_elem <= block.entities_count);
1582                                 CallData data = CallData(caller.system_id, sys,
1583                                     info, sys.m_update_delegate, first_block,
1584                                     cast(ushort)(full_blocks_count + 2),
1585                                     cast(ushort) first_elem, cast(ushort) last_elem);
1586                                 tmp_datas.add(data);
1587                                 first_elem = last_elem;
1588                                 blocks_count -= full_blocks_count + 1;
1589                                 first_block = block;
1590                                 if (last_elem == block.entities_count)
1591                                 {
1592                                     assert(block.next_block == null);
1593                                     first_block = null;
1594                                 }
1595                             }
1596                         }
1597                         else
1598                         {
1599                             uint last_elem = entities_per_job - entities_count;
1600                             assert(last_elem > 0);
1601                             CallData data = CallData(caller.system_id, sys,
1602                                 info, sys.m_update_delegate, first_block, 1,
1603                                 cast(ushort) first_elem, cast(ushort)(first_elem + last_elem));
1604                             tmp_datas.add(data);
1605                             first_elem += last_elem;
1606                             assert(first_elem <= first_block.entities_count);
1607                             //if job takes every entity, take next block
1608                             if (first_elem == first_block.entities_count)
1609                             {
1610                                 first_elem = 0;
1611                                 first_block = first_block.next_block;
1612                                 blocks_count--;
1613                             }
1614                         }
1615                         nextJob();
1616                         entities_count = 0;
1617                         goto begin;
1618                     }
1619                     else
1620                     {
1621                         //take whole info blocks
1622                         CallData data = CallData(caller.system_id, sys, info, sys.m_update_delegate,
1623                             first_block, cast(ushort) blocks_count, cast(ushort) first_elem);
1624                         tmp_datas.add(data);
1625                         entities_count += (blocks_count - 1) * info.max_entities
1626                             + info.last_block.entities_count - first_elem;
1627                     }
1628                 }
1629                 nextJob();
1630 
1631                 caller.job_group.jobs = sys.jobs[0 .. job_id];
1632                 (cast(void delegate(JobGroup) nothrow @nogc) m_dispatch_jobs)(caller.job_group); //sys.jobs[0 .. job_id]);
1633             }
1634         }
1635     }
1636 
1637     export void setMultithreadingCallbacks(void delegate(JobGroup) dispatch_callback,
1638         uint delegate() get_id_callback)
1639     {
1640         m_dispatch_jobs = cast(void delegate(JobGroup jobs) nothrow @nogc) dispatch_callback;
1641         m_thread_id_func = cast(uint delegate() nothrow @nogc) get_id_callback;
1642     }
1643 
1644     /************************************************************************************************************************
1645     Return size of single page (block). Every entity data block has size of page.
1646     */
1647     uint pageSize()
1648     {
1649         return m_page_size;
1650     }
1651 
1652     /************************************************************************************************************************
1653     Return number of pages in single block allocation. Library allocate defined number of pages at once and assign it's 
1654     for entities.
1655     */
1656     uint pagesInBlock()
1657     {
1658         return m_pages_in_block;
1659     }
1660 
1661     static void alignNum(ref ushort num, ushort alignment) nothrow @nogc pure
1662     {
1663         num = cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); //num += alignment - (num & (alignment - 1));
1664     }
1665 
1666     extern (C) static int compareUShorts(const void* a, const void* b) nothrow @nogc
1667     {
1668         ushort _a = *cast(ushort*) a;
1669         ushort _b = *cast(ushort*) b;
1670         if (_a < _b)
1671             return -1;
1672         else if (_a == _b)
1673             return 0;
1674         else
1675             return 1;
1676     }
1677 
1678     /************************************************************************************************************************
1679     Allocate EntityTemplate with all components from entity witch it's data and returns pointer to it.
1680     
1681     Params:
1682     entity_id = ID of entity from which should be created template
1683     fill_default = if true, components will be filled with default data, instead entity data will be taken
1684     */
1685     export EntityTemplate* allocateTemplate(EntityID entity_id, bool fill_default = false)
1686     {
1687         Entity* entity = getEntity(entity_id);
1688         EntitiesBlock* block = getMetaData(entity);
1689         EntityInfo* info = block.type_info;
1690 
1691         EntityTemplate* temp = Mallocator.make!EntityTemplate;
1692         temp.entity_data = Mallocator.makeArray!ubyte(info.size);
1693         temp.info = info;
1694 
1695         if (fill_default)
1696         {
1697             //fill components with default data
1698             foreach (comp; info.components)
1699             {
1700                 if (components[comp].size == 0)
1701                     continue;
1702                 memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp],
1703                     components[comp].init_data.ptr, components[comp].size);
1704             }
1705         }
1706         else
1707         {
1708             ushort index = block.entityIndex(entity);
1709             foreach (comp; info.components)
1710             {
1711                 if (components[comp].size == 0)
1712                     continue;
1713                 memcpy(cast(void*) temp.entity_data.ptr + info.tmpl_deltas[comp],
1714                     cast(void*) block + info.deltas[comp] + components[comp].size * index,
1715                     components[comp].size);
1716             }
1717         }
1718 
1719         return temp;
1720     }
1721 
1722     /************************************************************************************************************************
1723     Allocate EntityTemplate with specifed components and returns pointer to it.
1724     
1725     Params:
1726     components_ids = array of components allocated with template
1727     */
1728     export EntityTemplate* allocateTemplate(ushort[] components_ids)
1729     {
1730 
1731         ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * components_ids.length))[0
1732             .. components_ids.length];
1733         memcpy(ids.ptr, components_ids.ptr, ushort.sizeof * components_ids.length);
1734         //ids[0 .. $] = components_ids[];
1735         qsort(ids.ptr, ids.length, ushort.sizeof, &compareUShorts);
1736         {
1737             uint j = 1;
1738             foreach (i; 1 .. ids.length)
1739             {
1740                 assert(ids[i] != ushort.max);
1741                 if (ids[i] != ids[j - 1])
1742                 {
1743                     ids[j] = ids[i];
1744                     j++;
1745                 }
1746                 //else
1747                 //    debug assert(0, "Duplicated components in template!!!");
1748             }
1749             ids = ids[0 .. j];
1750         }
1751 
1752         EntityInfo* info = getEntityInfo(ids);
1753 
1754         EntityTemplate* temp = Mallocator.make!EntityTemplate;
1755         temp.entity_data = Mallocator.makeArray!ubyte(info.size);
1756         temp.info = info;
1757 
1758         //fill components with default data
1759         foreach (comp; info.components)
1760         {
1761             if (components[comp].size == 0)
1762                 continue;
1763             memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp],
1764                 components[comp].init_data.ptr, components[comp].size);
1765         }
1766 
1767         return temp;
1768     }
1769 
1770     /************************************************************************************************************************
1771     Allocate EntityTemplate from basic Template with modifications by adding and removing some components and returns pointer to it.
1772     Arrays of components needen't to be checked for repeated components, as function itself check if components exist in base template.
1773     
1774     Params:
1775     base_tmpl = template from which components sould be copied
1776     components_ids = array of new components to add
1777     remove_components_ids = array of components to remove from base template
1778     */
1779     export EntityTemplate* allocateTemplate(EntityTemplate* base_tmpl,
1780         ushort[] components_ids, ushort[] remove_components_ids = null)
1781     {
1782         size_t len = base_tmpl.info.components.length + components_ids.length;
1783         ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * len))[0 .. len];
1784         memcpy(ids.ptr, base_tmpl.info.components.ptr,
1785             ushort.sizeof * base_tmpl.info.components.length);
1786         memcpy(ids.ptr + base_tmpl.info.components.length, components_ids.ptr,
1787             ushort.sizeof * components_ids.length);
1788 
1789         qsort(ids.ptr, ids.length, ushort.sizeof, &compareUShorts);
1790         qsort(remove_components_ids.ptr, remove_components_ids.length,
1791             ushort.sizeof, &compareUShorts);
1792         {
1793             uint k = 0;
1794             uint j = 1;
1795             foreach (i; 1 .. ids.length)
1796             {
1797                 assert(ids[i] != ushort.max);
1798                 if (k < remove_components_ids.length)
1799                 {
1800                     while (k < remove_components_ids.length && remove_components_ids[k] < ids[i])
1801                     {
1802                         k++;
1803                     }
1804                     if (k < remove_components_ids.length)
1805                     {
1806                         if (remove_components_ids[k] == ids[i])
1807                             continue;
1808                     }
1809                 }
1810                 if (ids[i] != ids[j - 1])
1811                 {
1812                     ids[j] = ids[i];
1813                     j++;
1814                 }
1815                 //else
1816                 //    debug assert(0, "Duplicated components in template!!!");
1817             }
1818             ids = ids[0 .. j];
1819         }
1820 
1821         EntityInfo* info = getEntityInfo(ids);
1822 
1823         EntityTemplate* temp = Mallocator.make!EntityTemplate;
1824         temp.entity_data = Mallocator.makeArray!ubyte(info.size);
1825         temp.info = info;
1826 
1827         //fill components with default data and copy from base template
1828         foreach (comp; info.components)
1829         {
1830             if (comp < base_tmpl.info.tmpl_deltas.length
1831                 && base_tmpl.info.tmpl_deltas[comp] != ushort.max) //copy data from base component
1832                 {
1833                 if (components[comp].size == 0)
1834                     continue;
1835                 memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp],
1836                     base_tmpl.entity_data.ptr + base_tmpl.info.tmpl_deltas[comp],
1837                     components[comp].size);
1838             }
1839             else //fill with default data
1840             {
1841                 if (components[comp].size == 0)
1842                     continue;
1843                 memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp],
1844                     components[comp].init_data.ptr, components[comp].size);
1845             }
1846         }
1847 
1848         return temp;
1849     }
1850 
1851     /************************************************************************************************************************
1852     Allocate EntityTemplate copy.
1853     
1854     Params:
1855     copy_tmpl = template which should be copied
1856     */
1857     export EntityTemplate* allocateTemplate(EntityTemplate* copy_tmpl)
1858     {
1859         assert(copy_tmpl, "copy_tmpl can't be null");
1860         EntityTemplate* tmpl = Mallocator.make!EntityTemplate;
1861         tmpl.info = copy_tmpl.info;
1862         tmpl.entity_data = Mallocator.makeArray(copy_tmpl.entity_data);
1863         return tmpl;
1864     }
1865 
1866     /************************************************************************************************************************
1867     Returns entity type info.
1868     
1869     Params:
1870     ids = array of components
1871     */
1872     export EntityInfo* getEntityInfo(ushort[] ids)
1873     {
1874         if(ids.length == 0)ids = null;
1875         EntityInfo* info = entities_infos.get(ids, null);
1876         if (info is null)
1877         {
1878             info = Mallocator.make!EntityInfo;
1879 
1880             info.size = EntityID.sizeof;
1881             info.alignment = EntityID.alignof;
1882 
1883             if(ids is null)
1884             {
1885                 uint block_memory = cast(uint)(
1886                     m_page_size - EntitiesBlock.sizeof - info.size);
1887                 uint entites_in_block = block_memory / info.size;
1888                 info.max_entities = cast(ushort) entites_in_block;
1889             }
1890             else 
1891             {
1892                 uint components_size = EntityID.sizeof;
1893 
1894                 info.components = Mallocator.makeArray(ids);
1895                 info.deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1);
1896                 info.tmpl_deltas = Mallocator.makeArray!ushort(ids[$ - 1] + 1, ushort.max);
1897 
1898                 foreach (i, id; ids)
1899                 {
1900                     info.alignment = max(info.alignment, components[id].alignment);
1901                     alignNum(info.size, components[id].alignment);
1902                     info.tmpl_deltas[id] = info.size;
1903                     info.size += components[id].size;
1904                     components_size += components[id].size;
1905                 }
1906                 alignNum(info.size, info.alignment);
1907 
1908                 uint block_memory = cast(uint)(
1909                     m_page_size - EntitiesBlock.sizeof - (info.size - components_size));
1910                 //uint entity_comps_size = EntityID.sizeof;
1911                 uint mem_begin = EntitiesBlock.sizeof;
1912 
1913                 uint entites_in_block = block_memory / info.size; //entity_comps_size;
1914                 info.max_entities = cast(ushort) entites_in_block;
1915                 ushort current_delta = cast(ushort)(mem_begin + entites_in_block * EntityID.sizeof);
1916 
1917                 foreach (i, id; ids)
1918                 {
1919                     if (current_delta == 0)
1920                         current_delta = ushort.max;
1921                     alignNum(current_delta, components[id].alignment);
1922                     info.deltas[id] = cast(ushort) current_delta;
1923                     current_delta += entites_in_block * components[id].size;
1924                 }
1925 
1926                 info.comp_add_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length);
1927                 info.comp_rem_info = Mallocator.makeArray!(EntityInfo*)(info.deltas.length);
1928 
1929                 foreach (comp; info.components)
1930                 {
1931                     info.comp_add_info[comp] = info;
1932                     info.comp_rem_info[comp] = null;
1933                 }
1934             }
1935 
1936             info.systems = Mallocator.makeArray!bool(systems.length);
1937 
1938             foreach (i, ref system; systems)
1939             {
1940                 if (system.isAlive() == false)
1941                     continue;
1942                 if (system.m_empty)
1943                     continue;
1944                 if (system.m_update is null)
1945                 {
1946                     if (system.m_add_entity || system.m_remove_entity
1947                         || system.m_change_entity || system.m_event_callers.length)
1948                         connectListenerToEntityInfo(*info, cast(uint) i);
1949                     continue;
1950                 }
1951                 addSystemCaller(*info, cast(uint) i);
1952             }
1953 
1954             entities_infos.add(info.components, info);
1955 
1956             generateListeners(info);
1957         }
1958         return info;
1959     }
1960 
1961     private void generateListeners(EntityInfo* info) nothrow
1962     {
1963         if (info.add_listeners)
1964         {
1965             Mallocator.dispose(info.add_listeners);
1966             info.add_listeners = null;
1967         }
1968         if (info.remove_listeners)
1969         {
1970             Mallocator.dispose(info.remove_listeners);
1971             info.remove_listeners = null;
1972         }
1973         if (info.change_listeners)
1974         {
1975             Mallocator.dispose(info.change_listeners);
1976             info.change_listeners = null;
1977         }
1978         //allocate local data
1979         ushort[] tmp_add = (cast(ushort*) alloca(systems.length * ushort.sizeof))[0
1980             .. systems.length];
1981         ushort[] tmp_rem = (cast(ushort*) alloca(systems.length * ushort.sizeof))[0
1982             .. systems.length];
1983         ushort[] tmp_ch = (cast(ushort*) alloca(systems.length * ushort.sizeof))[0 .. systems
1984             .length];
1985         int add_len = 0;
1986         int rem_len = 0;
1987         int ch_len = 0;
1988         //assign listeners to lists
1989         foreach (i; 0 .. systems.length)
1990         {
1991             if (info.systems[i])
1992             {
1993                 System* system = &systems[i];
1994                 //onAddEntity listener
1995                 if (system.m_add_entity)
1996                 {
1997                     //find listener position by priority
1998                     int j;
1999                     for (j = 0; j < add_len; j++)
2000                     {
2001                         if (systems[i].priority < systems[tmp_add[j]].priority)
2002                             break;
2003                     }
2004                     add_len++;
2005                     //move elements after new listener
2006                     if (add_len < tmp_add.length)
2007                         for (int k = add_len; k > j; k--)
2008                         {
2009                             tmp_add[k] = tmp_add[k - 1];
2010                         }
2011                     //assign listener
2012                     tmp_add[j] = cast(ushort) i;
2013                 }
2014                 //onRemoveEntity listener
2015                 if (system.m_remove_entity)
2016                 {
2017                     //find listener position by priority
2018                     int j;
2019                     for (j = 0; j < rem_len; j++)
2020                     {
2021                         if (systems[i].priority < systems[tmp_rem[j]].priority)
2022                             break;
2023                     }
2024                     rem_len++;
2025                     //move elements after new listener
2026                     if (rem_len < tmp_add.length)
2027                         for (int k = rem_len; k > j; k--)
2028                         {
2029                             tmp_rem[k] = tmp_rem[k - 1];
2030                         }
2031                     //assign listener
2032                     tmp_rem[j] = cast(ushort) i;
2033                 }
2034                 //onChangeEntity listener
2035                 if (system.m_change_entity)
2036                 {
2037                     //find listener position by priority
2038                     int j;
2039                     for (j = 0; j < ch_len; j++)
2040                     {
2041                         if (systems[i].priority < systems[tmp_ch[j]].priority)
2042                             break;
2043                     }
2044                     ch_len++;
2045                     //move elements after new listener
2046                     if (ch_len < tmp_add.length)
2047                         for (int k = ch_len; k > j; k--)
2048                         {
2049                             tmp_ch[k] = tmp_ch[k - 1];
2050                         }
2051                     //assign listener
2052                     tmp_ch[j] = cast(ushort) i;
2053                 }
2054             }
2055         }
2056 
2057         if (add_len)
2058         {
2059             info.add_listeners = Mallocator.makeArray!ushort(add_len);
2060             memcpy(info.add_listeners.ptr, tmp_add.ptr, add_len * ushort.sizeof);
2061         }
2062 
2063         if (rem_len)
2064         {
2065             info.remove_listeners = Mallocator.makeArray!ushort(rem_len);
2066             memcpy(info.remove_listeners.ptr, tmp_rem.ptr, rem_len * ushort.sizeof);
2067         }
2068 
2069         if (ch_len)
2070         {
2071             info.change_listeners = Mallocator.makeArray!ushort(ch_len);
2072             memcpy(info.change_listeners.ptr, tmp_ch.ptr, ch_len * ushort.sizeof);
2073         }
2074     }
2075 
2076     export void connectListenerToEntityInfo(ref EntityInfo entity, uint system_id) nothrow @nogc
2077     {
2078         System* system = &systems[system_id];
2079 
2080         if (system.m_excluded_components)
2081         {
2082             foreach (id; system.m_excluded_components)
2083             {
2084                 foreach (id2; entity.components)
2085                 {
2086                     if (id == id2)
2087                         return;
2088                 }
2089             }
2090         }
2091 
2092         foreach (id; system.m_components)
2093         {
2094             foreach (i2, id2; entity.components)
2095             {
2096                 if (id2 == id)
2097                     goto is_;
2098             }
2099             return;
2100         is_:
2101         }
2102 
2103         ///call Custom Entity Filter test if function exists
2104         if (system.m_filter_entity && !(cast(bool function(void* system_pointer, EntityInfo* info) @nogc nothrow) system
2105                 .m_filter_entity)(system, &entity))
2106             return;
2107 
2108         entity.systems[system_id] = true;
2109     }
2110 
2111     export void addSystemCaller(uint system_id) nothrow @nogc
2112     {
2113         System* system = &systems[system_id];
2114 
2115         uint index = 0;
2116         for (; index < passes[system.m_pass].system_callers.length; index++)
2117         {
2118             if (passes[system.m_pass].system_callers[index].system_id == system_id)
2119                 return;
2120         }
2121 
2122         bool added = false;
2123         foreach (i, caller; passes[system.m_pass].system_callers)
2124         {
2125             if (systems[caller.system_id].priority > system.priority)
2126             {
2127                 SystemCaller* sys_caller = Mallocator.make!SystemCaller;
2128                 sys_caller.system_id = system.id;
2129                 sys_caller.job_group.caller = sys_caller;
2130                 system.m_any_system_caller = sys_caller;
2131                 passes[system.m_pass].system_callers.add(sys_caller, i);
2132                 added = true;
2133                 break;
2134             }
2135         }
2136         if (!added)
2137         {
2138             SystemCaller* sys_caller = Mallocator.make!SystemCaller;
2139             sys_caller.system_id = system.id;
2140             sys_caller.job_group.caller = sys_caller;
2141             system.m_any_system_caller = sys_caller;
2142             passes[system.m_pass].system_callers.add(sys_caller);
2143         }
2144     }
2145 
2146     export void addSystemCaller(ref EntityInfo info, uint system_id) nothrow @nogc
2147     {
2148         System* system = &systems[system_id];
2149 
2150         connectListenerToEntityInfo(info, system_id);
2151         if (!info.systems[system_id])
2152             return;
2153 
2154         uint index = 0;
2155         for (; index < passes[system.m_pass].system_callers.length; index++)
2156         {
2157             if (passes[system.m_pass].system_callers[index].system_id == system_id)
2158                 break;
2159         }
2160 
2161         if (index < passes[system.m_pass].system_callers.length)
2162         {
2163             passes[system.m_pass].system_callers[index].infos.add(&info);
2164         }
2165 
2166     }
2167 
2168     /************************************************************************************************************************
2169     Returns pointer to entity.
2170     
2171     Params:
2172     id = ID of entity
2173     */
2174     export Entity* getEntity(EntityID id) nothrow @nogc
2175     {
2176         return cast(Entity*) id_manager.getEntityPointer(id);
2177     }
2178 
2179     /************************************************************************************************************************
2180     Remove components from entity by IDs. Components will be removed on end of frame.
2181     
2182     Params:
2183     entity_id = ID of entity
2184     del_ids = array of components IDs
2185     */
2186     export void removeComponents(EntityID entity_id, ushort[] del_ids) nothrow @nogc
2187     {
2188         ThreadData* data = &threads[threadID];
2189         uint num = cast(uint) del_ids.length;
2190         data.changeEntitiesList.add(0);
2191         data.changeEntitiesList.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]);
2192         data.changeEntitiesList.add((cast(ubyte*)&num)[0 .. uint.sizeof]);
2193         data.changeEntitiesList.add((cast(ubyte*) del_ids.ptr)[0 .. num * 2]);
2194     }
2195 
2196     private void __removeComponents(EntityID entity_id, ushort[] del_ids)
2197     {
2198         Entity* entity = id_manager.getEntityPointer(entity_id);
2199         if (!entity)
2200             return;
2201         EntitiesBlock* block = getMetaData(entity);
2202         EntityInfo* info = block.type_info;
2203 
2204         //remove non-existing components
2205         uint num = cast(uint) del_ids.length;
2206         foreach_reverse (i; 0 .. num)
2207         {
2208             if (info.deltas.length <= del_ids[i] || info.deltas[del_ids[i]] == 0)
2209             {
2210                 num--;
2211                 del_ids[i] = del_ids[num];
2212             }
2213         }
2214 
2215         if (num == 0)
2216             return;
2217         del_ids = del_ids[0 .. num];
2218 
2219         //sort components
2220         qsort(del_ids.ptr, del_ids.length, ushort.sizeof, &compareUShorts);
2221 
2222         EntityInfo* new_info = info;
2223 
2224         foreach (id; del_ids)
2225         {
2226             new_info = new_info.getNewInfoRemove(id);
2227         }
2228 
2229         /*if (new_info == info)
2230             return;*/
2231 
2232         EntitiesBlock* new_block = findBlockWithFreeSpace(new_info);
2233         updateEntityInfoBlocks(new_info);
2234         assert(new_block.added_count == 0);
2235 
2236         void* start = new_block.dataBegin() + new_block.entities_count * EntityID.sizeof;
2237 
2238         Entity* new_entity = cast(Entity*) start;
2239         new_entity.id = entity.id;
2240         id_manager.update(*new_entity);
2241 
2242         uint ind = block.entityIndex(entity);
2243 
2244         if (info.remove_listeners)
2245         {
2246             foreach (listener; info.remove_listeners)
2247             {
2248                 if (!new_info.systems[listener])
2249                 {
2250                     callRemoveEntityListener(&systems[listener], info, block, ind, ind + 1);
2251                 }
2252             }
2253         }
2254 
2255         foreach (comp; new_info.components)
2256         {
2257             uint comp_size = components[comp].size;
2258             if (comp_size == 0)
2259                 continue;
2260             memcpy(cast(void*) new_block + new_info.deltas[comp] + new_block.entities_count * comp_size,
2261                 cast(void*) block + info.deltas[comp] + ind * comp_size, comp_size);
2262         }
2263 
2264         new_block.entities_count++;
2265         if (new_block != new_info.update_block)
2266             new_info.update_block = new_block;
2267 
2268         if (new_info.add_listeners)
2269         {
2270             foreach (listener; new_info.add_listeners)
2271             {
2272                 if (!info.systems[listener])
2273                 {
2274                     callAddEntityListener(&systems[listener], new_info, new_block,
2275                         new_block.entities_count - 1, new_block.entities_count);
2276                 }
2277             }
2278         }
2279 
2280         if (new_info.change_listeners)
2281         {
2282             foreach (listener; new_info.change_listeners)
2283             {
2284                 if (info.systems[listener])
2285                 {
2286                     callChangeEntityListener(&systems[listener], new_info, new_block,
2287                         new_block.entities_count - 1, new_block.entities_count, del_ids);
2288                 }
2289             }
2290         }
2291 
2292         removeEntityNoID(entity, block);
2293     }
2294 
2295     /************************************************************************************************************************
2296     Remove coponents from entity.
2297     
2298     Params:
2299     Components = components types to remove
2300     entity_id = ID of entity
2301     */
2302     void removeComponents(Components...)(EntityID entity_id)
2303     {
2304         const uint num = Components.length;
2305         ushort[num] del_ids;
2306         static foreach (i, comp; Components)
2307         {
2308             del_ids[i] = becsID!comp;
2309         }
2310 
2311         removeComponents(entity_id, del_ids);
2312     }
2313 
2314     private void __addComponents(EntityID entity_id, ushort[] new_ids, void*[] data_pointers)
2315     {
2316         uint num = cast(uint) new_ids.length;
2317         Entity* entity = id_manager.getEntityPointer(entity_id);
2318         if (!entity)
2319             return;
2320         EntitiesBlock* block = getMetaData(entity);
2321         EntityInfo* info = block.type_info;
2322 
2323         foreach_reverse (i; 0 .. num)
2324         {
2325             if (info.deltas.length > new_ids[i] && info.deltas[new_ids[i]] != 0)
2326             {
2327                 num--;
2328                 new_ids[i] = new_ids[num];
2329                 data_pointers[i] = data_pointers[num];
2330             }
2331         }
2332 
2333         if (num == 0)
2334             return;
2335         new_ids = new_ids[0 .. num];
2336 
2337         foreach (int i; 0 .. num)
2338         {
2339             ushort min = new_ids[i];
2340             int pos = i;
2341             foreach (int j; i .. num)
2342             {
2343                 if (new_ids[j] < min)
2344                 {
2345                     min = new_ids[j];
2346                     pos = j;
2347                 }
2348             }
2349             if (pos != i)
2350             {
2351                 ushort id = new_ids[i];
2352                 new_ids[i] = new_ids[pos];
2353                 new_ids[pos] = id;
2354                 void* ptr = data_pointers[i];
2355                 data_pointers[i] = data_pointers[pos];
2356                 data_pointers[pos] = ptr;
2357             }
2358         }
2359 
2360         EntityInfo* new_info = info;
2361 
2362         foreach (id; new_ids)
2363         {
2364             new_info = new_info.getNewInfoAdd(id);
2365         }
2366 
2367         assert(new_info != info);
2368         /*if (new_info == info)
2369             return;*/
2370 
2371         //EntityInfo* new_info = getEntityInfo(ids[0 .. len]);
2372 
2373         EntitiesBlock* new_block = findBlockWithFreeSpace(new_info);
2374         updateEntityInfoBlocks(new_info);
2375         assert(new_block.added_count == 0);
2376 
2377         void* start = new_block.dataBegin() + new_block.entities_count * EntityID.sizeof;
2378 
2379         Entity* new_entity = cast(Entity*) start;
2380         new_entity.id = entity.id;
2381         id_manager.update(*new_entity);
2382 
2383         uint j = 0;
2384         uint k = 0;
2385         uint ind = block.entityIndex(entity);
2386 
2387         if (info.remove_listeners)
2388         {
2389             foreach (listener; info.remove_listeners)
2390             {
2391                 if (!new_info.systems[listener])
2392                 {
2393                     callRemoveEntityListener(&systems[listener], info, block, ind, ind + 1);
2394                 }
2395             }
2396         }
2397 
2398         foreach (id; new_info.components) //ids[0 .. len])
2399         {
2400             uint size = components[id].size;
2401             void* dst = void;
2402             if (size != 0)
2403                 dst = cast(void*) new_block + new_info.deltas[id] + (new_block.entities_count)
2404                     * size;
2405 
2406             if (k >= new_ids.length)
2407             {
2408                 if (size != 0)
2409                     memcpy(dst, cast(void*) block + info.deltas[id] + ind * size, size);
2410                 j++;
2411             }
2412             else if (j >= info.components.length || id == new_ids[k])
2413             {
2414                 if (size != 0)
2415                     memcpy(dst, data_pointers[k], size);
2416                 k++;
2417             }
2418             else
2419             {
2420                 assert(id != new_ids[0]);
2421                 if (size != 0)
2422                     memcpy(dst, cast(void*) block + info.deltas[id] + ind * size, size);
2423                 j++;
2424             }
2425         }
2426 
2427         new_block.entities_count++;
2428         if (new_block != new_info.update_block)
2429             new_info.update_block = new_block;
2430 
2431         if (new_info.add_listeners)
2432         {
2433             foreach (listener; new_info.add_listeners)
2434             {
2435                 if (!info.systems[listener])
2436                 {
2437                     callAddEntityListener(&systems[listener], new_info, new_block,
2438                         new_block.entities_count - 1, new_block.entities_count);
2439                 }
2440             }
2441         }
2442 
2443         if (new_info.change_listeners)
2444         {
2445             foreach (listener; new_info.change_listeners)
2446             {
2447                 if (info.systems[listener])
2448                 {
2449                     callChangeEntityListener(&systems[listener], new_info, new_block,
2450                         new_block.entities_count - 1, new_block.entities_count, new_ids);
2451                 }
2452             }
2453         }
2454 
2455         removeEntityNoID(entity, block);
2456     }
2457 
2458     /************************************************************************************************************************
2459     Add components to entity. Components will be added on end of frame.
2460     
2461     Params:
2462     entity_id = ID of entity to remove
2463     comps = components to add
2464     */
2465     void addComponents(Components...)(const EntityID entity_id, Components comps) nothrow @nogc
2466     {
2467         const uint num = Components.length;
2468 
2469         ComponentRef[num] _comps;
2470         static foreach (i, comp; comps)
2471         {
2472             _comps[i] = ComponentRef(&comp, becsID!(typeof(comp)));
2473         }
2474         addComponents(entity_id, _comps);
2475 
2476     }
2477 
2478     export void addComponents(const EntityID entity_id, ComponentRef[] comps) nothrow @nogc
2479     {
2480         uint num = cast(uint) comps.length;
2481         ThreadData* data = &threads[threadID];
2482         data.changeEntitiesList.add(cast(ubyte) 1u);
2483         data.changeEntitiesList.add((cast(ubyte*)&entity_id)[0 .. EntityID.sizeof]);
2484         data.changeEntitiesList.add((cast(ubyte*)&num)[0 .. uint.sizeof]);
2485         foreach (ref_; comps)
2486         {
2487             data.changeEntitiesList.add((cast(ubyte*)&ref_.component_id)[0 .. ushort.sizeof]);
2488         }
2489         foreach (ref_; comps)
2490         {
2491             if (components[ref_.component_id].size != 0)
2492                 data.changeEntitiesList.add(
2493                     (cast(ubyte*) ref_.ptr)[0 .. components[ref_.component_id].size]);
2494         }
2495     }
2496 
2497     /************************************************************************************************************************
2498     Free template memory.
2499     
2500     Params:
2501     template_ = pointer entity template allocated by EntityManager.
2502     */
2503     export void freeTemplate(EntityTemplate* template_) @nogc nothrow
2504     {
2505         Mallocator.dispose(template_.entity_data);
2506         Mallocator.dispose(template_);
2507     }
2508 
2509     /************************************************************************************************************************
2510     Add copy of entity to system and returns pointer to it. Added copy has same data as copied entity. Returen pointer is 
2511     valid only before one from commit(), begin() or end() will be called. To save entity to further use you should save ID 
2512     instead of pointer.
2513     *
2514     *Params:
2515     *id = ID of entity to be copyied.
2516     */
2517     export Entity* addEntityCopy(EntityID id)
2518     {
2519         Entity* entity = getEntity(id);
2520         EntitiesBlock* block = getMetaData(entity);
2521         EntityInfo* info = block.type_info;
2522 
2523         ushort index = block.entityIndex(entity);
2524 
2525         ushort new_index = 0;
2526         EntitiesBlock* new_block;
2527         do
2528         {
2529             new_block = findBlockWithFreeSpaceMT(info);
2530             new_index = new_block.added_count.atomicOp!"+="(1);
2531         }
2532         while (new_block.entities_count + new_index > info.max_entities);
2533 
2534         ushort new_id = cast(ushort)(new_block.entities_count + new_index - 1);
2535         const void* data_begin = new_block.dataBegin();
2536         const void* start = data_begin + EntityID.sizeof * new_id;
2537 
2538         foreach (i, comp; info.components)
2539         {
2540             ushort size = components[comp].size;
2541             if (size != 0)
2542                 memcpy(cast(void*) new_block + info.deltas[comp] + new_id * size,
2543                     cast(void*) block + info.deltas[comp] + size * index, size);
2544 
2545             if (components[comp].create_callback)
2546             {
2547                 components[comp].create_callback(
2548                     cast(void*) new_block + info.deltas[comp] + new_id * size);
2549             }
2550         }
2551 
2552         if (new_index == 1 && info.update_block == new_block)
2553             threads[threadID].infosToUpdate.add(info);
2554 
2555         Entity* new_entity = cast(Entity*) start;
2556         new_entity.id = id_manager.getNewID();
2557         id_manager.update(*new_entity);
2558 
2559         return new_entity;
2560     }
2561 
2562     /************************************************************************************************************************
2563     Add entity to system. Returen pointer is valid only before one from commit(), begin() or end() will be called. To save entity to further
2564     use you should save ID instead of pointer.
2565     
2566     Params:
2567     tmpl = pointer entity template allocated by EntityManager. Can be null in which case empty entity would be added (entity without components)
2568     */
2569     export Entity* addEntity(EntityTemplate* tmpl)
2570     {
2571         return addEntity(tmpl, null);
2572     }
2573 
2574     /************************************************************************************************************************
2575     Add entity to system. Returen pointer is valid only before one from commit(), begin() or end() will be called. To save entity to further
2576     use you should save ID instead of pointer.
2577     
2578     Params:
2579     tmpl = pointer entity template allocated by EntityManager. Can be null in which case empty entity would be added (entity without components)
2580     replacement = list of components references to used. Memory form list replace data from template inside new entity. Should be used only for data which vary between most entities (like 3D position etc.)
2581     */
2582     export Entity* addEntity(EntityTemplate* tmpl, ComponentRef[] replacement)
2583     {
2584         EntityInfo* info = void;
2585         if(tmpl)info = tmpl.info;
2586         else info = getEntityInfo(null);
2587 
2588         ushort index = 0;
2589         EntitiesBlock* block;
2590         do
2591         {
2592             block = findBlockWithFreeSpaceMT(info);
2593             index = block.added_count.atomicOp!"+="(1);
2594         }
2595         while (block.entities_count + index > info.max_entities);
2596 
2597         uint id = (block.entities_count + index - 1); //block.added_count);
2598 
2599         void* data_begin = block.dataBegin();
2600         void* start = data_begin + EntityID.sizeof * id;
2601 
2602         foreach (comp; info.components)
2603         {
2604             uint size = components[comp].size;
2605             if (size != 0)
2606                 memcpy(cast(void*) block + info.deltas[comp] + size * id,
2607                     tmpl.entity_data.ptr + info.tmpl_deltas[comp], size);
2608         }
2609 
2610         foreach (comp; replacement)
2611         {
2612             if (comp.component_id < info.deltas.length)
2613             {
2614                 ushort delta = info.deltas[comp.component_id];
2615                 if (delta != 0)
2616                 {
2617                     uint size = components[comp.component_id].size;
2618                     if (size != 0)
2619                         memcpy(cast(void*) block + delta + size * id, comp.ptr, size);
2620                 }
2621             }
2622         }
2623 
2624         foreach (i, comp; info.components)
2625         {
2626             if (components[comp].create_callback)
2627             {
2628                 components[comp].create_callback(
2629                     cast(void*) block + info.deltas[comp] + id * components[comp].size);
2630             }
2631         }
2632 
2633         if (index == 1 && info.update_block == block)
2634             threads[threadID].infosToUpdate.add(info);
2635 
2636         Entity* entity = cast(Entity*) start;
2637         entity.id = id_manager.getNewID();
2638         id_manager.update(*entity);
2639 
2640         return entity;
2641     }
2642 
2643     /************************************************************************************************************************
2644     Return block with free space for selected EntityInfo.
2645     */
2646     private EntitiesBlock* findBlockWithFreeSpace(EntityInfo* info) nothrow @nogc
2647     {
2648         EntitiesBlock* block = info.last_block;
2649 
2650         if (block is null)
2651         {
2652             block = cast(EntitiesBlock*) allocator.getBlock();
2653             *block = EntitiesBlock(info);
2654             block.id = 0;
2655             info.first_block = block;
2656             info.last_block = block;
2657             info.update_block = block;
2658         }
2659         else if (block.entities_count >= info.max_entities)
2660         {
2661             EntitiesBlock* new_block = cast(EntitiesBlock*) allocator.getBlock();
2662             *new_block = EntitiesBlock(info);
2663             new_block.prev_block = block;
2664             block.next_block = new_block;
2665             new_block.id = cast(ushort)(block.id + 1);
2666             block = new_block;
2667             info.last_block = block;
2668             ///make sure that update_block point to unfilled block
2669             if (info.update_block.entities_count == info.max_entities)
2670             {
2671                 assert(!info.update_block.added_count);
2672                 info.update_block = block;
2673             }
2674         }
2675         return block;
2676     }
2677 
2678     /************************************************************************************************************************
2679     Return block with free space for selected EntityInfo. Additional this function is multithread safe.
2680     */
2681     private EntitiesBlock* findBlockWithFreeSpaceMT(EntityInfo* info)
2682     {
2683         EntitiesBlock* block = info.last_block;
2684 
2685         if (block is null)
2686         {
2687             entity_block_alloc_mutex.lock();
2688             scope (exit)
2689                 entity_block_alloc_mutex.unlock();
2690 
2691             if (info.last_block != null)
2692                 return info.last_block;
2693 
2694             block = cast(EntitiesBlock*) allocator.getBlock();
2695             *block = EntitiesBlock(info);
2696             block.id = 0;
2697             info.first_block = block;
2698             info.last_block = block;
2699             info.update_block = block;
2700         }
2701         else if (block.entities_count + block.added_count >= info.max_entities)
2702         {
2703             EntitiesBlock* last_block = info.last_block;
2704 
2705             entity_block_alloc_mutex.lock();
2706             scope (exit)
2707                 entity_block_alloc_mutex.unlock();
2708 
2709             if (info.last_block !is last_block)
2710                 return info.last_block;
2711 
2712             EntitiesBlock* new_block = cast(EntitiesBlock*) allocator.getBlock();
2713             *new_block = EntitiesBlock(info);
2714             new_block.prev_block = block;
2715             block.next_block = new_block;
2716             new_block.id = cast(ushort)(block.id + 1);
2717             block = new_block;
2718             info.last_block = block;
2719             ///make sure that update_block point to unfilled block
2720             if (info.update_block.entities_count == info.max_entities)
2721             {
2722                 assert(!info.update_block.added_count);
2723                 info.update_block = block;
2724             }
2725         }
2726         return block;
2727     }
2728 
2729     /************************************************************************************************************************
2730     Remove entity by ID. Entity will be removed on frame end.
2731     
2732     Params:
2733     id = id of entity to remove
2734     */
2735     export void removeEntity(EntityID id)
2736     {
2737         threads[threadID].entitesToRemove.add(id);
2738     }
2739 
2740     private void __removeEntity(EntityID id) nothrow @nogc
2741     {
2742         //get entity and block meta data pointers
2743         Entity* entity = id_manager.getEntityPointer(id);
2744 
2745         if (entity is null)
2746             return; //return if entity doesn't exist
2747 
2748         EntitiesBlock* block = getMetaData(entity);
2749 
2750         EntityInfo* info = block.type_info;
2751         if (info.remove_listeners)
2752         {
2753             uint pos = block.entityIndex(entity);
2754 
2755             callRemoveEntityListeners(info, block, pos, pos + 1);
2756         }
2757 
2758         id_manager.releaseID(id); //release id from manager
2759 
2760         removeEntityNoID(entity, block, true);
2761     }
2762 
2763     private void removeEntityNoID(Entity* entity, EntitiesBlock* block,
2764         bool call_destructors = false) nothrow @nogc
2765     {
2766         EntityInfo* info = block.type_info;
2767 
2768         updateEntityInfoBlocks(info);
2769 
2770         assert(info.last_block.added_count == 0);
2771         assert(info.last_block.entities_count > 0);
2772 
2773         info.last_block.entities_count--;
2774 
2775         uint pos = block.entityIndex(entity);
2776 
2777         if (call_destructors)
2778         {
2779             foreach (comp; info.components)
2780             {
2781                 if (components[comp].destroy_callback)
2782                 {
2783                     components[comp].destroy_callback(cast(
2784                             void*) block + info.deltas[comp] + pos * components[comp].size);
2785                 }
2786             }
2787         }
2788 
2789         if (block !is info.last_block || pos != block.entities_count)
2790         {
2791             foreach (comp; info.components)
2792             {
2793                 uint size = components[comp].size;
2794                 if (size == 0)
2795                     continue;
2796                 void* src = cast(void*) info.last_block + info.deltas[comp];
2797                 void* dst = cast(void*) block + info.deltas[comp];
2798                 memcpy(dst + pos * size, src + info.last_block.entities_count * size, size);
2799             }
2800 
2801             block = info.last_block;
2802             entity.id = *cast(EntityID*)(block.dataBegin() + block.entities_count * EntityID.sizeof);
2803 
2804             id_manager.update(*entity);
2805         }
2806 
2807         block = info.last_block;
2808         if (block.entities_count == 0)
2809         {
2810             assert(info.update_block is block);
2811             info.last_block = block.prev_block;
2812             if (info.first_block is block)
2813             {
2814                 info.first_block = null;
2815             }
2816             if (block.prev_block)
2817             {
2818                 block.prev_block.next_block = null;
2819                 info.update_block = block.prev_block;
2820                 assert(block.prev_block.added_count == 0);
2821                 //block.prev_block.added_count.atomicStore(cast(ushort)0);
2822             }
2823             allocator.freeBlock(block);
2824         }
2825     }
2826 
2827     /************************************************************************************************************************
2828     functions return MetaData of page.
2829     
2830     Params:
2831     pointer = pointer to any data of entity (i.e. component data pointer)
2832     */
2833     export EntitiesBlock* getMetaData(const void* pointer) nothrow @nogc
2834     {
2835         return cast(EntitiesBlock*)(cast(size_t) pointer & (~cast(size_t)(m_page_size - 1)));
2836     }
2837 
2838     private bool changeEntities()
2839     {
2840         bool has_work = false;
2841         //foreach (ref ThreadData thread; threads)thread.swapToChange();
2842         foreach (ref ThreadData thread; threads)
2843         {
2844             uint index = 0;
2845             uint len = cast(uint) thread.changeEntitiesListPrev.length;
2846             if (len)
2847                 has_work = true;
2848             void*[32] pointers; // = (cast(void**) alloca(num * (void*).sizeof))[0 .. num];
2849             while (index < len)
2850             {
2851                 if (!thread.changeEntitiesListPrev[index++])
2852                 {
2853                     EntityID id = *cast(EntityID*)&thread.changeEntitiesListPrev[index];
2854                     index += EntityID.sizeof;
2855                     uint num = *cast(uint*)&thread.changeEntitiesListPrev[index];
2856                     index += uint.sizeof;
2857                     ushort[] ids; // = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num];
2858                     ids = (cast(ushort*)&thread.changeEntitiesListPrev[index])[0 .. num];
2859                     index += ushort.sizeof * num;
2860                     __removeComponents(id, ids);
2861                 }
2862                 else
2863                 {
2864                     EntityID id = *cast(EntityID*)&thread.changeEntitiesListPrev[index];
2865                     index += EntityID.sizeof;
2866                     uint num = *cast(uint*)&thread.changeEntitiesListPrev[index];
2867                     index += uint.sizeof;
2868                     ushort[] ids; // = (cast(ushort*) alloca(num * ushort.sizeof))[0 .. num];
2869                     ids = (cast(ushort*)&thread.changeEntitiesListPrev[index])[0 .. num];
2870                     index += ushort.sizeof * num;
2871                     //void*[] pointers = (cast(void**) alloca(num * (void*).sizeof))[0 .. num];
2872                     foreach (i; 0 .. num)
2873                     {
2874                         pointers[i] = &thread.changeEntitiesListPrev[index];
2875                         index += components[ids[i]].size;
2876                     }
2877 
2878                     __addComponents(id, ids, pointers[0 .. num]);
2879                 }
2880             }
2881             thread.changeEntitiesListPrev.clear();
2882         }
2883         return has_work;
2884     }
2885 
2886     private void callAddEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow
2887     {
2888         foreach (listener; info.add_listeners)
2889         {
2890             System* system = &systems[listener];
2891             callAddEntityListener(system, info, block, begin, end);
2892         }
2893     }
2894 
2895     private static void callAddEntityListener(System* system, EntityInfo* info,
2896         EntitiesBlock* block, int begin, int end) @nogc nothrow
2897     {
2898         ListenerCallData data;
2899         data.system = system;
2900         data.block = block;
2901         data.begin = begin;
2902         data.end = end;
2903         (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_add_entity)(data);
2904     }
2905 
2906     private void callRemoveEntityListeners(EntityInfo* info, EntitiesBlock* block, int begin,
2907         int end) @nogc nothrow
2908     {
2909         foreach (listener; info.remove_listeners)
2910         {
2911             System* system = &systems[listener];
2912             callRemoveEntityListener(system, info, block, begin, end);
2913         }
2914     }
2915 
2916     private static void callRemoveEntityListener(System* system,
2917         EntityInfo* info, EntitiesBlock* block, int begin, int end) @nogc nothrow
2918     {
2919         ListenerCallData data;
2920         data.system = system;
2921         data.block = block;
2922         data.begin = begin;
2923         data.end = end;
2924         (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_remove_entity)(data);
2925     }
2926 
2927     private void callChangeEntityListener(System* system, EntityInfo* info,
2928         EntitiesBlock* block, int begin, int end, ushort[] ch_ids) @nogc nothrow
2929     {
2930         int i = 0;
2931         int j = 0;
2932         bool is_ = false;
2933         while (1)
2934         {
2935             if (ch_ids[i] == system.m_optional_components[j])
2936             {
2937                 is_ = true;
2938                 break;
2939             }
2940             else if (ch_ids[i] > system.m_optional_components[j])
2941             {
2942                 j++;
2943                 if (j >= system.m_optional_components.length)
2944                     break;
2945             }
2946             else
2947             {
2948                 i++;
2949                 if (i >= ch_ids.length)
2950                     break;
2951             }
2952         }
2953         if (!is_)
2954             return;
2955 
2956         ListenerCallData data;
2957         data.system = system;
2958         data.block = block;
2959         data.begin = begin;
2960         data.end = end;
2961         (cast(void function(ref ListenerCallData) nothrow @nogc) system.m_change_entity)(data);
2962     }
2963 
2964     private void updateEntityInfoBlocks(EntityInfo* info) nothrow @nogc
2965     {
2966         while (info.last_block.added_count)
2967         {
2968             EntitiesBlock* block = info.update_block;
2969             assert(block !is null);
2970             if (block.entities_count == info.max_entities)
2971             {
2972                 assert(!block.added_count);
2973                 block = block.next_block;
2974             }
2975             assert(!block.prev_block || !block.prev_block.added_count);
2976             info.update_block = info.last_block;
2977 
2978             while (block)
2979             {
2980                 assert(block.added_count.atomicLoad() > 0);
2981                 updateBlock(block);
2982                 block = block.next_block;
2983             }
2984         }
2985         assert(info.last_block is info.update_block);
2986     }
2987 
2988     private void updateBlock(EntitiesBlock* block) @nogc nothrow
2989     {
2990         //if(block.added_count == 0)return;
2991         assert(block.added_count != 0);
2992         EntityInfo* info = block.type_info;
2993         ushort entities_count = block.entities_count;
2994         block.entities_count += block.added_count;
2995         if (block.entities_count > block.type_info.max_entities)
2996         {
2997             block.entities_count = block.type_info.max_entities;
2998         }
2999         block.added_count.atomicStore(cast(ushort) 0);
3000 
3001         if (info.add_listeners)
3002         {
3003             callAddEntityListeners(info, block, entities_count, block.entities_count);
3004         }
3005     }
3006 
3007     private bool updateBlocks()
3008     {
3009         bool has_work = false;
3010         foreach (ref ThreadData thread; threads)
3011         {
3012             if (thread.infosToUpdatePrev.length)
3013                 has_work = true;
3014             foreach (info; thread.infosToUpdatePrev)
3015             {
3016                 updateEntityInfoBlocks(info);
3017             }
3018             thread.infosToUpdatePrev.clear();
3019         }
3020         return has_work;
3021     }
3022 
3023     private bool removeEntities() nothrow @nogc
3024     {
3025         bool has_work = false;
3026         //foreach (ref ThreadData thread; threads)thread.swapToRemove();
3027         foreach (ref ThreadData thread; threads)
3028         {
3029             if (thread.entitiesToRemovePrev.length)
3030                 has_work = true;
3031             foreach (id; thread.entitiesToRemovePrev)
3032             {
3033                 __removeEntity(id);
3034             }
3035             thread.entitiesToRemovePrev.clear();
3036         }
3037         return has_work;
3038     }
3039 
3040     private bool updateEvents() nothrow @nogc
3041     {
3042         bool has_work = false;
3043         // bool empty = true;
3044         //while (1)
3045         //{
3046         //event_manager.swapCurrent();
3047         uint current_index;
3048         if (event_manager.current_index == 0)
3049             current_index = cast(uint) threads.length;
3050         else
3051             current_index = 0;
3052         foreach (i, event; event_manager.events)
3053         {
3054             foreach (first_block; event.first_blocks[current_index .. current_index + threads
3055                     .length])
3056             {
3057                 EventManager.EventBlock* block = first_block;
3058                 if (block)
3059                     has_work = true;
3060                 // {
3061                 //     has_work = true;
3062                 //     //empty = false;
3063                 // }
3064                 while (block)
3065                 {
3066                     EventCallData call_data;
3067                     void* event_pointer = cast(void*) block + event.data_offset;
3068                     foreach (j; 0 .. block.count)
3069                     {
3070                         call_data.event = event_pointer + EntityID.sizeof;
3071                         EntityID entity_id = *cast(EntityID*)(event_pointer);
3072                         Entity* entity = id_manager.getEntityPointer(entity_id);
3073                         if (entity)
3074                         {
3075                             call_data.block = getMetaData(entity);
3076                             call_data.id = call_data.block.entityIndex(entity);
3077                             call_data.entity = entity;
3078 
3079                             foreach (caller; events[i].callers)
3080                             {
3081                                 if (call_data.block.type_info.systems[caller.system.m_id] == false
3082                                     || !caller.system.enabled || !caller.system.willExecute)
3083                                     continue;
3084                                 call_data.system_pointer = caller.system.m_system_pointer;
3085                                 (cast(void function(ref EventCallData) nothrow @nogc) caller
3086                                         .callback)(call_data);
3087                             }
3088                         }
3089                         if (events[i].destroy_callback)
3090                             events[i].destroy_callback(event_pointer);
3091                         event_pointer += events[i].size + EntityID.sizeof;
3092                     }
3093                     block = block.next;
3094                 }
3095             }
3096         }
3097         // if (empty)
3098         //     break;
3099         // empty = true;
3100         //}
3101         return has_work;
3102     }
3103 
3104     private void swapData() nothrow @nogc
3105     {
3106         event_manager.swapCurrent();
3107         foreach (ref ThreadData thread; threads)
3108         {
3109             thread.swapData();
3110         }
3111     }
3112 
3113     export void commit()
3114     {
3115         bool has_work = true;
3116         while (has_work)
3117         {
3118             swapData();
3119 
3120             has_work = false;
3121             has_work |= updateBlocks();
3122             // has_work |= changeEntities();
3123             // has_work |= removeEntities();
3124             has_work |= updateEvents();
3125 
3126             id_manager.optimize();
3127             has_work |= updateBlocks();
3128             has_work |= changeEntities();
3129             has_work |= removeEntities();
3130         }
3131         event_manager.clearEvents();
3132     }
3133 
3134     /************************************************************************************************************************
3135     Begin of update process. Should be called before any update is called.
3136     */
3137     export void begin()
3138     {
3139 
3140         commit();
3141         m_call_data_allocator.clear();
3142 
3143         foreach (ref system; systems)
3144         {
3145             if (system.isAlive() == false)
3146                 continue;
3147             if (system.enabled && system.m_begin)
3148                 system.m_execute = (cast(bool function(void*)) system.m_begin)(
3149                     system.m_system_pointer);
3150         }
3151     }
3152 
3153     /************************************************************************************************************************
3154     End of update process. Should be called after every update function.
3155     */
3156     export void end()
3157     {
3158 
3159         foreach (ref system; systems)
3160         {
3161             if (system.isAlive() == false)
3162                 continue;
3163 
3164             if (system.enabled && system.m_end)
3165                 (cast(void function(void*)) system.m_end)(system.m_system_pointer);
3166         }
3167 
3168         commit();
3169     }
3170 
3171     /*private void getThreadID() nothrow @nogc
3172     {
3173         if (m_thread_id_func)
3174             thread_id = (cast(uint delegate() nothrow @nogc) m_thread_id_func)();
3175         else
3176             thread_id = 0;
3177     }*/
3178 
3179     void sendEvent(Ev)(EntityID id, Ev event) nothrow @nogc
3180     {
3181         event_manager.sendEvent(id, event, threadID);
3182     }
3183 
3184     private void generateDependencies() nothrow @nogc
3185     {
3186         foreach (pass_id, pass; passes)
3187         {
3188             foreach (caller; pass.system_callers)
3189             {
3190                 caller.system = &systems[caller.system_id];
3191                 if (caller.exclusion)
3192                     Mallocator.dispose(caller.exclusion);
3193                 if (caller.dependencies)
3194                     Mallocator.dispose(caller.dependencies);
3195             }
3196             uint index = 0;
3197             SystemCaller*[] exclusion;
3198             exclusion = (cast(SystemCaller**) alloca((SystemCaller*)
3199                     .sizeof * pass.system_callers.length))[0 .. pass.system_callers.length];
3200             foreach (caller; pass.system_callers)
3201             {
3202                 index = 0;
3203                 ///gets systems which are excluding each other
3204                 out_for: foreach (caller2; pass.system_callers)
3205                 {
3206                     if (caller is caller2)
3207                         continue;
3208 
3209                     ///check for external dependencies
3210                     foreach (cmp; caller.system.m_readonly_dependencies)
3211                     {
3212                         foreach (cmp2; caller2.system.m_writable_dependencies)
3213                         {
3214                             if (cmp == cmp2)
3215                             {
3216                                 exclusion[index++] = caller2;
3217                                 continue out_for;
3218                             }
3219                         }
3220                     }
3221                     foreach (cmp; caller.system.m_writable_dependencies)
3222                     {
3223                         foreach (cmp2; caller2.system.m_readonly_dependencies)
3224                         {
3225                             if (cmp == cmp2)
3226                             {
3227                                 exclusion[index++] = caller2;
3228                                 continue out_for;
3229                             }
3230                         }
3231                         foreach (cmp2; caller2.system.m_writable_dependencies)
3232                         {
3233                             if (cmp == cmp2)
3234                             {
3235                                 exclusion[index++] = caller2;
3236                                 continue out_for;
3237                             }
3238                         }
3239                     }
3240 
3241                     ///check for component dependencies
3242                     foreach (cmp; caller.system.m_read_only_components)
3243                     {
3244                         foreach (cmp2; caller2.system.m_writable_components)
3245                         {
3246                             if (cmp == cmp2)
3247                             {
3248                                 exclusion[index++] = caller2;
3249                                 continue out_for;
3250                             }
3251                         }
3252                     }
3253                     foreach (cmp; caller.system.m_writable_components)
3254                     {
3255                         foreach (cmp2; caller2.system.m_read_only_components)
3256                         {
3257                             if (cmp == cmp2)
3258                             {
3259                                 exclusion[index++] = caller2;
3260                                 continue out_for;
3261                             }
3262                         }
3263                         foreach (cmp2; caller2.system.m_writable_components)
3264                         {
3265                             if (cmp == cmp2)
3266                             {
3267                                 exclusion[index++] = caller2;
3268                                 continue out_for;
3269                             }
3270                         }
3271                     }
3272                 }
3273 
3274                 if (index > 0)
3275                 {
3276                     caller.exclusion = Mallocator.makeArray(exclusion[0 .. index]);
3277                 }
3278                 else
3279                     caller.exclusion = null;
3280             }
3281 
3282             extern (C) static int compareSystems(const void* a, const void* b)
3283             {
3284                 SystemCaller* _a = *cast(SystemCaller**) a;
3285                 SystemCaller* _b = *cast(SystemCaller**) b;
3286                 if (_a.system.priority < _b.system.priority)
3287                     return -1;
3288                 else if (_a.system.priority == _b.system.priority)
3289                 {
3290                     if (_a.exclusion.length < _b.exclusion.length)
3291                         return -1;
3292                     else if (_a.exclusion.length == _b.exclusion.length)
3293                         return 0;
3294                     else
3295                         return 1;
3296                 }
3297                 else
3298                     return 1;
3299             }
3300 
3301             qsort(pass.system_callers.array.ptr, pass.system_callers.length,
3302                 (SystemCaller*).sizeof, &compareSystems);
3303 
3304             foreach (i, caller; pass.system_callers)
3305                 caller.job_group.id = cast(uint) i;
3306 
3307             int priority = int.min;
3308             uint beg = 0;
3309             index = 0;
3310             foreach (i, caller; pass.system_callers)
3311             {
3312                 index = 0;
3313                 foreach (ex; caller.exclusion)
3314                 {
3315                     if (ex.job_group.id > caller.job_group.id)
3316                         continue;
3317 
3318                     exclusion[index++] = ex;
3319                 }
3320 
3321                 if (index > 0)
3322                 {
3323                     caller.dependencies = Mallocator.makeArray(exclusion[0 .. index]);
3324                     caller.job_group.dependencies = Mallocator.makeArray!(JobGroup*)(index);
3325 
3326                     foreach (j, dep; caller.dependencies)
3327                     {
3328                         caller.job_group.dependencies[j] = &dep.job_group;
3329                     }
3330                 }
3331                 else
3332                     caller.dependencies = null;
3333             }
3334         }
3335     }
3336 
3337     const(UpdatePass)* getPass(const(char)[] name)
3338     {
3339         ushort id = getPassID(name);
3340         if (id == ushort.max)
3341             return null;
3342         return passes[id];
3343     }
3344 
3345     ushort getPassID(const(char)[] name)
3346     {
3347         return passes_map.get(name, ushort.max);
3348     }
3349 
3350     /************************************************************************************************************************
3351     Component info;
3352     */
3353     struct ComponentInfo
3354     {
3355         export ~this() nothrow @nogc
3356         {
3357         }
3358         ///Component size
3359         ushort size;
3360         ///Component data alignment
3361         ushort alignment;
3362         ///Initialization data
3363         ubyte[] init_data;
3364         ///Pointer to component destroy callback
3365         void function(void* pointer) nothrow @nogc destroy_callback;
3366         //void* destroy_callback;
3367         ///Pointer to component create callback
3368         void function(void* pointer) nothrow @nogc create_callback;
3369         //void* create_callback;
3370     }
3371 
3372     struct EventCaller
3373     {
3374         System* system;
3375         void* callback;
3376     }
3377 
3378     struct EventCallData
3379     {
3380         EntitiesBlock* block;
3381         void* system_pointer;
3382         void* event;
3383         Entity* entity;
3384         ushort id;
3385     }
3386 
3387     struct EventInfo
3388     {
3389         ushort size;
3390         ushort alignment;
3391         EventCaller[] callers;
3392         void function(void* pointer) nothrow @nogc destroy_callback;
3393     }
3394 
3395     /************************************************************************************************************************
3396     Entity type info.
3397     */
3398     struct EntityInfo
3399     {
3400         ///Returns number of blocks
3401         uint blocksCount() nothrow @nogc
3402         {
3403             if (last_block)
3404                 return last_block.id + 1;
3405             else
3406                 return 0;
3407         }
3408 
3409         ///Returns number of non empty blocks
3410         uint nonEmptyBlocksCount() nothrow @nogc
3411         {
3412             EntitiesBlock* block = last_block;
3413             while (1)
3414             {
3415                 if (block is null)
3416                     return 0;
3417                 if (block.entities_count == 0)
3418                     block = block.prev_block;
3419                 else
3420                     return block.id + 1;
3421             }
3422         }
3423 
3424         EntityInfo* getNewInfoAdd(ushort id)
3425         {
3426             if (comp_add_info.length <= id)
3427             {
3428                 EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)(
3429                     gEntityManager.components.length);
3430                 if (comp_add_info !is null)
3431                 {
3432                     //new_infos[0 .. comp_add_info.length] = comp_add_info[0 .. $];
3433                     memcpy(new_infos.ptr, comp_add_info.ptr, (EntityInfo*)
3434                             .sizeof * comp_add_info.length);
3435                     Mallocator.dispose(comp_add_info);
3436                 }
3437                 comp_add_info = new_infos;
3438             }
3439             if (comp_add_info[id])
3440                 return comp_add_info[id];
3441 
3442             ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (components.length + 1)))[0
3443                 .. components.length + 1];
3444             uint len = 0;
3445 
3446             foreach (comp; components)
3447             {
3448                 if (id > comp)
3449                 {
3450                     ids[len++] = comp;
3451                 }
3452                 else
3453                 {
3454                     ids[len++] = id;
3455                     ids[len++] = comp;
3456                     foreach (comp2; components[len - 1 .. $])
3457                     {
3458                         ids[len++] = comp2;
3459                     }
3460                     break;
3461                 }
3462             }
3463             if (components.length == 0 || id > components[$ - 1])
3464                 ids[len++] = id;
3465 
3466             assert(len == components.length + 1);
3467 
3468             EntityInfo* new_info = gEntityManager.getEntityInfo(ids);
3469 
3470             comp_add_info[id] = new_info;
3471             return new_info;
3472         }
3473 
3474         EntityInfo* getNewInfoRemove(ushort id) return
3475         {
3476             /*if (comp_rem_info.length <= id)
3477             {
3478                 EntityInfo*[] new_infos = Mallocator.makeArray!(EntityInfo*)(
3479                         gEntityManager.components.length, &this);
3480                 if (comp_rem_info !is null)
3481                 {
3482                     //new_infos[0 .. comp_rem_info.length] = comp_rem_info[0 .. $];
3483                     memcpy(new_infos.ptr, comp_rem_info.ptr, (EntityInfo*)
3484                             .sizeof * comp_rem_info.length);
3485                     Mallocator.dispose(comp_rem_info);
3486                 }
3487                 comp_rem_info = new_infos;
3488             }*/
3489             if (comp_rem_info[id])
3490                 return comp_rem_info[id];
3491 
3492             ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * (components.length - 1)))[0
3493                 .. components.length - 1];
3494             uint len = 0;
3495 
3496             foreach (comp; components)
3497             {
3498                 if (id != comp)
3499                 {
3500                     ids[len++] = comp;
3501                 }
3502             }
3503             assert(len != components.length);
3504             //if (len == components.length)
3505             //    return &this;
3506 
3507             assert(len == components.length - 1);
3508 
3509             EntityInfo* new_info = gEntityManager.getEntityInfo(ids[0 .. len]);
3510 
3511             comp_rem_info[id] = new_info;
3512             return new_info;
3513         }
3514 
3515         export bool hasComponent(ushort component_id)
3516         {
3517             if (component_id >= deltas.length || !deltas[component_id])
3518                 return false;
3519             return true;
3520         }
3521 
3522         export ~this() @nogc nothrow
3523         {
3524             if (components)
3525                 Mallocator.dispose(components);
3526             if (deltas)
3527                 Mallocator.dispose(deltas);
3528             if (tmpl_deltas)
3529                 Mallocator.dispose(tmpl_deltas);
3530             if (comp_add_info)
3531                 Mallocator.dispose(comp_add_info);
3532             if (comp_rem_info)
3533                 Mallocator.dispose(comp_rem_info);
3534             if (systems)
3535                 Mallocator.dispose(systems);
3536             if (add_listeners)
3537                 Mallocator.dispose(add_listeners);
3538             if (remove_listeners)
3539                 Mallocator.dispose(remove_listeners);
3540             if (change_listeners)
3541                 Mallocator.dispose(change_listeners);
3542         }
3543 
3544         ///entity components
3545         ushort[] components;
3546 
3547         ///deltas in memory for components in EntitiesBlock
3548         ushort[] deltas;
3549         ///deltas in memory for components in EntityTemplate
3550         ushort[] tmpl_deltas;
3551 
3552         ///cached new infos after adding component
3553         EntityInfo*[] comp_add_info;
3554         ///cached new infos after removing component
3555         EntityInfo*[] comp_rem_info;
3556 
3557         ///alignment of whole entity
3558         ushort alignment; //unused in linear-layout TODO: to remove
3559         ///size of entity (with alignment respect)
3560         ushort size;
3561         ///max number of entities in block
3562         ushort max_entities;
3563 
3564         ///array of systems which will update this entity
3565         bool[] systems;
3566         ///systems which are listening for added entities
3567         ushort[] add_listeners;
3568         ///systems which are listening for removed entities
3569         ushort[] remove_listeners;
3570         ///systems which are listening for changed entities (changed in term of contained components)
3571         ushort[] change_listeners;
3572 
3573         ///pointer to first block/page
3574         EntitiesBlock* first_block;
3575         ///pointer to last block
3576         EntitiesBlock* last_block;
3577         ///pointer to last updated block
3578         EntitiesBlock* update_block;
3579     }
3580 
3581     /************************************************************************************************************************
3582     Meta data of every block of entities (contained at the begining of block).
3583     */
3584     struct EntitiesBlock
3585     {
3586         ///return pointer to first element in block
3587         export void* dataBegin() nothrow @nogc pure return
3588         {
3589             ushort dif = EntitiesBlock.sizeof;
3590             return cast(void*)&this + dif;
3591         }
3592 
3593         export ushort entityIndex(const(Entity)* entity) nothrow @nogc pure
3594         {
3595             static if (EntityID.sizeof == 8)
3596                 return cast(ushort)((cast(void*) entity - dataBegin()) >> 3);
3597             else
3598                 return cast(ushort)((cast(void*) entity - dataBegin()) / EntityID.sizeof());
3599         }
3600 
3601         ///pointer to Entity type info
3602         EntityInfo* type_info = null;
3603         ///number of entities in block
3604         ushort entities_count = 0;
3605         ///number of new entities in block
3606         shared ushort added_count = 0;
3607         //ushort added_count = 0;
3608         ///block id
3609         ushort id = 0;
3610         ///maximum number of entities in block
3611         //ushort max_entities = 0;
3612         ///pointer to next block/page
3613         EntitiesBlock* next_block = null;
3614         ///pointer to next block/page
3615         EntitiesBlock* prev_block = null;
3616         //there is a loooot of data (some kB of memory, pure magic)
3617     }
3618 
3619     /************************************************************************************************************************
3620     Structure with data used to calling System calls.
3621     
3622     <i>first_block</i>, <i>begin</i>, <i>end</i>, <i>blocks</i> parameters are used
3623     to call partial info update 
3624     */
3625     struct CallData
3626     {
3627         export void update() nothrow @nogc
3628         {
3629             (cast(SytemFuncType) system.m_update)(this);
3630         }
3631 
3632         ///system ID. Used to update system pointer after system reload.
3633         uint system_id;
3634         ///pointer to used system
3635         System* system;
3636         ///poiner to Entity type info
3637         EntityManager.EntityInfo* info;
3638         ///delegate function to call (by default it's delegate to onUpdate call)
3639         void delegate() update_delegate;
3640 
3641         ///pointer to first block into process (if 0 then first block will be used)
3642         EntitiesBlock* first_block;
3643         ///number of blocks to update (if 0 then update all)
3644         ushort blocks;
3645         ///index of first element in first block
3646         ushort begin;
3647         ///index of last element in last block
3648         ushort end;
3649         ///current thread index
3650         uint thread_id;
3651         //current job index
3652         uint job_id;
3653     }
3654 
3655     struct ListenerCallData
3656     {
3657         System* system;
3658         EntitiesBlock* block;
3659         uint begin;
3660         uint end;
3661     }
3662 
3663     struct Job
3664     {
3665         CallData[] callers;
3666         uint id;
3667 
3668         export void execute() nothrow @nogc
3669         {
3670             foreach (ref caller; callers)
3671             {
3672                 caller.thread_id = gEntityManager.threadID();
3673                 caller.job_id = id;
3674                 caller.update();
3675             }
3676         }
3677     }
3678 
3679     struct JobGroup
3680     {
3681         Job[] jobs;
3682         JobGroup*[] dependencies;
3683         uint id;
3684         SystemCaller* caller;
3685         //uint max_jobs;
3686     }
3687 
3688     struct SystemCaller
3689     {
3690         export ~this() nothrow @nogc
3691         {
3692             if (dependencies)
3693             {
3694                 Mallocator.dispose(dependencies);
3695             }
3696             if (exclusion)
3697             {
3698                 Mallocator.dispose(exclusion);
3699             }
3700             if (job_group.dependencies)
3701                 Mallocator.dispose(job_group.dependencies);
3702         }
3703 
3704         uint system_id;
3705         System* system;
3706         Vector!(EntityInfo*) infos;
3707         SystemCaller*[] dependencies;
3708         SystemCaller*[] exclusion;
3709         JobGroup job_group;
3710     }
3711 
3712     struct ThreadData
3713     {
3714         ref Vector!EntityID entitesToRemove() @nogc nothrow return
3715         {
3716             return entities_to_remove[data_index];
3717         }
3718 
3719         ref SimpleVector changeEntitiesList() @nogc nothrow return
3720         {
3721             return change_entities_list[data_index];
3722         }
3723 
3724         ref Vector!(EntityInfo*) infosToUpdate() @nogc nothrow return
3725         {
3726             return infos_to_update[data_index];
3727         }
3728 
3729         ref Vector!EntityID entitiesToRemovePrev() @nogc nothrow return
3730         {
3731             return entities_to_remove[1 - data_index];
3732         }
3733 
3734         ref SimpleVector changeEntitiesListPrev() @nogc nothrow return
3735         {
3736             return change_entities_list[1 - data_index];
3737         }
3738 
3739         ref Vector!(EntityInfo*) infosToUpdatePrev() @nogc nothrow return
3740         {
3741             return infos_to_update[1 - data_index];
3742         }
3743 
3744     private:
3745 
3746         void swapData() @nogc nothrow
3747         {
3748             data_index = cast(ubyte)(1 - data_index);
3749         }
3750 
3751         Vector!EntityID[2] entities_to_remove;
3752         SimpleVector[2] change_entities_list;
3753         Vector!(EntityInfo*)[2] infos_to_update;
3754 
3755         ubyte data_index = 0;
3756     }
3757 
3758     export struct UpdatePass
3759     {
3760         export ~this() nothrow @nogc
3761         {
3762             assert(name);
3763             if (name)
3764                 Mallocator.dispose(name);
3765             foreach (caller; system_callers)
3766             {
3767                 Mallocator.dispose(caller);
3768             }
3769             system_callers.clear();
3770         }
3771 
3772         char[] name;
3773         Vector!(SystemCaller*) system_callers;
3774     }
3775 
3776     export uint threadID() @nogc nothrow
3777     {
3778         if (m_thread_id_func)
3779             return m_thread_id_func();
3780         else
3781             return 0;
3782     }
3783 
3784     ThreadData[] threads;
3785 
3786     Vector!(UpdatePass*) passes;
3787 
3788     bool register_state = false;
3789 
3790     alias SytemFuncType = void function(ref EntityManager.CallData data) nothrow @nogc;
3791 
3792     ///Single page size. Must be power of two.
3793     int m_page_size = 32768; //32768; //4096;
3794     ///Number of pages in block.
3795     int m_pages_in_block = 128;
3796 
3797     IDManager id_manager;
3798     BlockAllocator allocator;
3799 
3800     EventManager event_manager;
3801 
3802     void delegate(JobGroup jobs) nothrow @nogc m_dispatch_jobs;
3803     uint delegate() nothrow @nogc m_thread_id_func;
3804 
3805     HashMap!(ushort[], EntityInfo*) entities_infos;
3806     HashMap!(char[], ushort) systems_map;
3807     HashMap!(char[], ushort) components_map;
3808     HashMap!(const(char)[], ushort) events_map;
3809     HashMap!(const(char)[], ushort) passes_map;
3810     HashMap!(const(char)[], ushort) external_dependencies_map;
3811     Vector!System systems;
3812     Vector!ComponentInfo components;
3813     Vector!EventInfo events;
3814 
3815     //Mutex add_mutex;
3816     Mutex* entity_block_alloc_mutex;
3817 
3818     CallDataAllocator m_call_data_allocator;
3819     struct CallDataAllocator
3820     {
3821         struct Block
3822         {
3823             CallData[256] data;
3824             uint allocated = 0;
3825         }
3826 
3827         export ~this() nothrow @nogc
3828         {
3829             foreach (block; blocks)
3830             {
3831                 Mallocator.dispose(block);
3832             }
3833             blocks.clear();
3834         }
3835 
3836         Vector!(Block*) blocks;
3837         uint id;
3838 
3839         void clear() nothrow @nogc
3840         {
3841             if (blocks.length > 0)
3842                 foreach (block; blocks[0 .. id + 1])
3843                 {
3844                     block.allocated = 0;
3845                 }
3846             id = 0;
3847             //blocks.clear();
3848         }
3849 
3850         CallData[] getCallData(uint num) nothrow @nogc
3851         {
3852             if (blocks.length == 0)
3853             {
3854                 Block* new_block = Mallocator.make!Block;
3855                 blocks.add(new_block);
3856             }
3857 
3858             Block* block = blocks[id];
3859             if (block.allocated + num >= 256)
3860             {
3861                 id++;
3862                 if (id == blocks.length)
3863                 {
3864                     Block* new_block = Mallocator.make!Block;
3865                     blocks.add(new_block);
3866                 }
3867                 block = blocks[id];
3868             }
3869 
3870             CallData[] ret = block.data[block.allocated .. block.allocated + num];
3871             block.allocated += num;
3872             return ret;
3873         }
3874     }
3875 
3876 }