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