1 /++
2 Scene and instance control module.
3 
4 Macros:
5     LREF = <a href="#$1">$1</a>
6     HREF = <a href="$1">$2</a>
7 
8 Authors: $(HREF https://github.com/TodNaz,TodNaz)
9 Copyright: Copyright (c) 2020 - 2021, TodNaz.
10 License: $(HREF https://github.com/TodNaz/Tida/blob/master/LICENSE,MIT)
11 +/
12 module tida.scenemanager;
13 
14 import tida.instance;
15 import tida.localevent;
16 import tida.scene;
17 import tida.render;
18 import tida.instance;
19 import tida.component;
20 import tida.event;
21 import tida.fps;
22 import core.thread;
23 
24 /++
25 Mistakes of using communication between the manager and the game cycle.
26 +/
27 enum APIError : uint
28 {
29     succes, /// Errors are not detected.
30     ThreadIsNotExists, /// The stream with which it was necessary to interact - does not exist.
31     UnkownResponse
32 }
33 
34 /++
35 Commands that should execute the game cycle.
36 +/
37 enum APIType : uint
38 {
39     None, /// None
40     ThreadCreate, /// Create the specified number of threads.
41     ThreadPause,
42     ThreadResume,
43     ThreadClose,
44     GameClose,
45     ThreadClosed,
46     ThreadRebindThreadID
47 }
48 
49 /++
50 Container to send a message to the game cycle.
51 +/
52 struct APIResponse
53 {
54     uint code; /// Command thah should execute the game cycle.
55     uint value; /// Value response
56 }
57 
58 __gshared SceneManager _sceneManager;
59 
60 /// Scene manager instance.
61 SceneManager sceneManager() @trusted
62 {
63     return _sceneManager;
64 }
65 
66 /// Allocates memory under the scene manager.
67 void initSceneManager() @trusted
68 {
69     _sceneManager = new SceneManager();
70 }
71 
72 version (unittest)
73 {
74     auto defaultCamera() @safe
75     {
76         return null;
77     }
78 } else
79 auto defaultCamera() @safe
80 {
81     import tida.game : renderer, window;
82     import tida.shape;
83     import tida.vector;
84     import tida.runtime;
85 
86     auto camera = new Camera();
87     camera.shape = Shape!float.Rectangle(
88         vecZero!float, 
89         window.fullscreen ? 
90             vec!float(runtime.monitorSize) :
91             vec!float(window.width, window.height)
92     );
93     camera.port = camera.shape;
94             
95     return camera;
96 }
97 
98 /++
99 Class describing scene manager.
100 
101 Performs the functions of switching the context of the scenes, memorize
102 the list for subsequent circulation, the ability to execute elementary
103 events, give an instance access to the current scene or scene, which is
104 involved in the event.
105 
106 To transfer the context, use the `gotoin`. Learn the current scene - `current`.
107 previous - `previous` Contact precisely to the global object - `scenemanager`.
108 +/
109 final class SceneManager
110 {
111     import std.algorithm : canFind;
112     import core.sync.mutex;
113 
114 private:
115     alias RecoveryDelegate = void delegate(ref Scene) @safe;
116     alias LazyInfo = Scene delegate() @safe;
117     alias LazyGroupFunction = Scene[string] delegate() @safe;
118 
119     struct LazyGroupInfo
120     {
121         string[] names;
122         LazyGroupFunction spawnFunction;
123     }
124 
125     Scene[string] _scenes;
126     Scene _current;
127     Scene _previous;
128     Scene _ofbegin;
129     Scene _ofend;
130     Scene _initable;
131     Scene _restarted;
132 
133     RecoveryDelegate[string] recovDelegates;
134     LazyInfo[string] recovLazySpawns;
135 
136     LazyInfo[string] lazySpawns;
137     LazyGroupInfo[] lazyGroupSpawns;
138 
139     bool _thereGoto;
140 
141     bool updateThreads = false;
142 
143     shared(Mutex) instanceMutex;
144 
145 public @safe:
146     size_t countStartThreads = 0;
147     size_t maxThreads = 3;
148     size_t functionPerThread = 80;
149 
150     this() @safe
151     {
152         instanceMutex = new shared Mutex;
153     }
154 
155     /++
156     A state indicating whether an instance transition is in progress. 
157     Needed to synchronize the stream.
158     +/
159     @property bool isThereGoto() nothrow pure
160     {
161         return _thereGoto;
162     }
163     
164     /// List scenes
165     @property Scene[string] scenes() nothrow pure
166     {
167         return _scenes;
168     }
169 
170     /++
171     The first added scene.
172 
173     It can be overridden so that when the game
174     is restarted, the manager will jump to the
175     scene from this line:
176     ---
177     sceneManager.ofbegin = myScene;
178     sceneManager.gameRestart();
179     ---
180     +/
181     @property Scene ofbegin() nothrow pure
182     {
183         return _ofbegin;
184     }
185 
186     /++
187     The last added scene.
188     +/
189     @property Scene ofend() nothrow pure
190     {
191         return _ofend;
192     }
193 
194     /++
195     The previous scene that was active.
196     +/
197     @property Scene previous() nothrow pure
198     {
199         return _previous;
200     }
201 
202     /++
203     A scene that restarts at the moment.
204     +/
205     @property Scene restarted() nothrow pure
206     {
207         return _restarted;
208     }
209 
210     /++
211     Restarting the game.
212 
213     Please note that this function causes complete deletion and creation of all
214     scenes in the framework. Therefore, it is recommended to load all resources
215     through the resource manager so that when you restart all scenes of the
216     constructor of such scenes, the resources are not loaded again.
217 
218     Also note that there are resources in the game that may not be reloaded by
219     this function. For this there is an event `GameRestart`, in it put the
220     implementation of the function that fixes such problems.
221     +/
222     void gameRestart() @trusted
223     {
224         foreach (ref scene; scenes)
225         {
226             _restarted = scene;
227 
228             foreach (fun; scene.events.GameRestartFunctions) fun();
229             foreach (instance; scene.list())
230             {
231                 foreach (fun; instance.events.IGameRestartFunctions) fun();
232                 scene.instanceDestroy!InMemory(instance);
233             }
234 
235             recovDelegates[scene.name](scene);
236 
237             _restarted = null;
238         }
239 
240         gotoin(ofbegin);
241     }
242 
243     /++
244     Link to the current scene.
245 
246     Please note that such a pointer is correct only in those events that
247     differ from `init`,` restart`, `leave`, they can not go at all on the
248     current one that you hoped. Example: In the initialization event, you
249     want access to the scene, which is initialized, but here you can make
250     a mistake - the pointer leads to the previous scene. You can access
251     the current through `sceneManager.initable`.
252 
253     See_Also:
254         tida.scene.manager.SceneManager.initable
255     +/
256     @property Scene current() nothrow pure
257     {
258         return _current;
259     }
260 
261     /++
262     The reference to the scene, which is undergoing context change
263     processing.
264 
265     The use of such a link is permissible only in context transmission
266     events, otherwise, it is possible to detect the scene leading nowhere.
267     +/
268     @property Scene initable() nothrow pure
269     {
270         return _initable;
271     }
272 
273     /++
274     The reference to the current stage, as if it is under initialization,
275     whether it is during a restart or without them.
276 
277     This link is selected depending on what is happening. If this is caused
278     during the change of context, it will lead exactly the scene that
279     receives the context. If the manager restarts the game, the link leads
280     to the scene, which is now restarting if there are no such events, then
281     the scene leads to the current working scene.
282 
283     Examples:
284     ---
285     @FunEvent!Init
286     void Initialization() @safe
287     {
288         assert(sceneManager.initable is sceneManager.context); // ok
289     }
290 
291     @FunEvent!Step
292     void Move() @safe
293     {
294         assert(sceneManager.current is sceneManager.context); // ok
295     }
296 
297     @FunEvent!GameRestart
298     void onGameRestart() @safe
299     {
300         assert(sceneManager.restarted is sceneManager.context); // ok
301     }
302     ---
303     +/
304     @property Scene context() nothrow pure
305     {
306         return _initable is null ? (_restarted is null ? _current : _restarted) : _initable;
307     }
308 
309     /++
310     Calls a trigger for the current scene, as well as its instances.
311 
312     Triggers are required for custom signal and events. By calling, you can
313     force to pull functions with special attributes, for example:
314     ---
315     alias SpecEvent = Trigger("SpecialEvent");
316 
317     @SpecEvent
318     void onSpec() @safe { ... }
319     ...
320     sceneManager.trigger("SpecialEvent");
321     // Will cause the exact event to be called by calling the function,
322     // only for the scene that is being held in the context.
323     ---
324 
325     Params:
326         name = Trigger name.
327     +/
328     void trigger(string name) @trusted
329     {
330         auto scene = this.context();
331 
332         foreach (fun; scene.events.OnTriggerFunctions)
333         {
334             if (fun.ev.name == name)
335             {
336                 fun.fun();
337             }
338         }
339 
340         foreach (instance; scene.list())
341         {
342             foreach (fun; instance.events.IOnTriggerFunctions)
343             {
344                 if (fun.ev.name == name)
345                 {
346                     fun.fun();
347                 }
348             }
349         }
350     }
351 
352     unittest
353     {
354         enum onSaysHi = Trigger("onSaysHi");
355 
356         initSceneManager();
357 
358         static class Test : Scene
359         {
360             bool isSayHi = false;
361 
362             @onSaysHi void onSayHi() @safe
363             {
364                 isSayHi = true;
365             }
366         }
367 
368         Test test;
369 
370         sceneManager.add (test = new Test());
371         sceneManager.gotoin(test);
372 
373         sceneManager.trigger("onSaysHi");
374 
375         assert (test.isSayHi);
376     }
377 
378     /++
379     Challenge the trigger in all scenes and copies that will be there.
380     It is the call that goes from everyone, and not the current scene
381 
382     Params:
383         name = Trigger name.
384     +/
385     void globalTrigger(string name) @trusted
386     {
387         foreach (scene; scenes)
388         {
389             foreach (fun; scene.events.OnTriggerFunctions)
390             {
391                 if (fun.ev.name == name)
392                 {
393                     fun.fun();
394                 }
395             }
396 
397             foreach (instance; scene.list())
398             {
399                 foreach (fun; instance.events.IOnTriggerFunctions)
400                 {
401                     if (fun.ev.name == name)
402                     {
403                         fun.fun();
404                     }
405                 }
406             }
407         }
408     }
409 
410     unittest
411     {
412         enum onSaysHi = Trigger("onSaysHi");
413 
414         initSceneManager();
415 
416         static class Test : Scene
417         {
418             bool isSayHi = false;
419 
420             @onSaysHi void onSayHi() @safe
421             {
422                 isSayHi = true;
423             }
424         }
425 
426         static class Test2 : Scene
427         {
428             bool isSayHi = false;
429 
430             @onSaysHi void onSayHi() @safe
431             {
432                 isSayHi = true;
433             }
434         }
435 
436         Test test;
437         Test2 test2;
438 
439         sceneManager.add (test = new Test());
440         sceneManager.add (test2 = new Test2());
441         sceneManager.inbegin();
442 
443         sceneManager.trigger("onSaysHi");
444         assert (!test2.isSayHi);
445 
446         sceneManager.globalTrigger("onSaysHi");
447         assert (test2.isSayHi);
448     }
449 
450     /++
451     Checks if the scene is in the scene list.
452 
453     Params:
454         scene = Scene.
455     +/
456     bool hasScene(Scene scene) @trusted
457     {
458         return _scenes.values.canFind(scene);
459     }
460 
461     /++
462     Checks for the existence of a scene by its original class.
463 
464     Params:
465         Name = Class name.
466     +/
467     bool hasScene(Name)()
468     {
469         return _scenes.values.canFind!(e => (cast(Name) e) !is null);
470     }
471 
472     /++
473     Checks if there is a scene with the specified name.
474 
475     Params:
476         name = Scene name.
477     +/
478     bool hasScene(string name)
479     {
480         return _scenes.values.canFind!(e => e.name == name);
481     }
482 
483     /++
484     Function for lazy loading scenes. In the chalon only specifies the scene.
485     At the same time, it will be listed in the scene list, however,
486     its resources will not be loaded until the control goes to it.
487     After the context change, it does not need to be re-shipped.
488 
489     Params:
490         T = Lazy scene.
491     +/
492     void lazyAdd(T)()
493     if (isScene!T)
494     {
495         auto fun = {
496             T scene = new T();
497             if (scene.name == [])
498                 scene.name = T.stringof;
499 
500             add!T(scene);
501 
502             size_t countThreads = maxThreads;
503             if (countStartThreads > countThreads)
504                 countThreads = countStartThreads;
505             scene.initThread(countThreads);
506 
507             return scene;
508         };
509 
510         lazySpawns[T.stringof] = fun;
511         recovLazySpawns[T.stringof] = fun;
512     }
513 
514     unittest
515     {
516         initSceneManager();
517 
518         static class LazyScene : Scene
519         {
520             int a = 0;
521 
522             this() @safe
523             {
524                 a = 32;
525             }
526         }
527 
528         sceneManager.lazyAdd!(LazyScene)();
529         assert(!sceneManager.hasScene!LazyScene);
530 
531         sceneManager.gotoin!LazyScene;
532 
533         assert(sceneManager.hasScene!LazyScene);
534     }
535 
536     void lazyGroupAdd(T...)()
537     {
538         size_t countThreads = 0;
539 
540         auto fun = () @trusted {
541             Scene[string] rtScenes;
542 
543             static foreach (SceneType; T)
544             {
545                 static assert(isScene!SceneType, "It not a Scene!");
546 
547                 mixin("
548                 SceneType __scene" ~ SceneType.stringof ~ " = new SceneType();
549                 if (__scene" ~ SceneType.stringof ~ ".name.length == 0)
550                     __scene" ~ SceneType.stringof ~ ".name = \"" ~ SceneType.stringof ~ "\";
551 
552                 add(__scene" ~ SceneType.stringof ~ ");
553 
554                 countThreads = maxThreads;
555                 if (countStartThreads > countThreads)
556                     countThreads = countStartThreads;
557 
558                 __scene" ~ SceneType.stringof ~ ".initThread(countThreads);
559 
560                 rtScenes[\"" ~ SceneType.stringof ~ "\"] = __scene" ~ SceneType.stringof ~ ";
561                 ");
562             }
563 
564             return rtScenes;
565         };
566 
567         string[] names;
568         static foreach (SceneType; T)
569         {
570             names ~= SceneType.stringof;
571         }
572 
573         this.lazyGroupSpawns ~= LazyGroupInfo(names, fun);
574     }
575 
576     unittest
577     {
578         initSceneManager();
579 
580         static class LazyScene1 : Scene
581         {
582             int a = 0;
583 
584             this() @safe
585             {
586                 a = 32;
587             }
588         }
589 
590         static class LazyScene2 : Scene
591         {
592             int a = 0;
593 
594             this() @safe
595             {
596                 a = 48;
597             }
598         }
599 
600         static class LazyScene3 : Scene
601         {
602             int a = 0;
603 
604             this() @safe
605             {
606                 a = 64;
607             }
608         }
609 
610         static class LazyScene4 : Scene
611         {
612             int a = 0;
613 
614             this() @safe
615             {
616                 a = 98;
617             }
618         }
619 
620         sceneManager.lazyGroupAdd!(LazyScene1, LazyScene2);
621         sceneManager.lazyGroupAdd!(LazyScene3, LazyScene4);
622 
623         assert(!sceneManager.hasScene!LazyScene1);
624         assert(!sceneManager.hasScene!LazyScene3);
625 
626         sceneManager.gotoin!LazyScene2;
627 
628         assert(sceneManager.hasScene!LazyScene1);
629         assert(!sceneManager.hasScene!LazyScene3);
630 
631         sceneManager.gotoin!LazyScene4;
632 
633         assert(sceneManager.hasScene!LazyScene1);
634         assert(sceneManager.hasScene!LazyScene3);
635     }
636 
637     /++
638     Adds a scene to the list.
639 
640     Params:
641         scene = Scene.
642     +/
643     void add(T)(T scene)
644     {
645         static assert(isScene!T, "`" ~ T.stringof ~ "` is not a scene!");
646         exploreScene!T(scene);
647 
648         if (scene.name == "")
649             scene.name = T.stringof;
650 
651         if (_ofbegin is null)
652             _ofbegin = scene;
653 
654         recovDelegates[scene.name] = (ref Scene bscene) @safe
655         {
656             bool isSceneBegin = (ofbegin is bscene);
657 
658             bscene = new T();
659             exploreScene!T(cast(T) bscene);
660             _scenes[bscene.name] = bscene;
661 
662             if (isSceneBegin) _ofbegin = bscene;
663         };
664 
665         _scenes[scene.name] = scene;
666     }
667 
668     template hasMatch(alias attrib, alias AttribType)
669     {
670         enum hasMatch = is(typeof(attrib) == AttribType) || is(attrib == AttribType) ||
671                         is(typeof(attrib) : AttribType) || is(attrib : AttribType);
672     }
673 
674     template hasAttrib(T, AttribType, string member)
675     {
676         import std.traits : isFunction, isSafe, getUDAs;
677 
678         alias same = __traits(getMember, T, member);
679 
680         static if (isFunction!(same) && isSafe!(same))
681         {
682             alias attributes = __traits(getAttributes, same);
683 
684             static if (attributes.length != 0)
685             {
686                 static foreach (attrib; attributes)
687                 {
688                     static if (hasMatch!(attrib, AttribType))
689                     {
690                         static assert(isSafe!(same),
691                         "The function `" ~ member ~"` does not guarantee safe execution.");
692 
693                         enum hasAttrib = true;
694                         enum found = true;
695                     }
696                 }
697 
698                 static if (!__traits(compiles, found))
699                 {
700                     enum hasAttrib = false;
701                 }
702             } else
703             {
704                 enum hasAttrib = false;
705             }
706         } else
707         {
708             enum hasAttrib = false;
709         }
710     }
711 
712     template attributeIn(T, AttribType, string member)
713     {
714         alias same = __traits(getMember, T, member);
715         alias attributes = __traits(getAttributes, same);
716 
717         static foreach (attrib; attributes)
718         {
719             static if (hasMatch!(attrib, AttribType))
720             {
721                 enum attributeIn = attrib;
722             }
723         }   
724     }
725 
726     /++
727     A function to receive events that were described inside 
728     the object's implementation.
729     
730     It is necessary if you need to manually call any functions 
731     without using the scene manager. (The object doesn't have to be added somewhere for the function to work).
732     
733     Params:
734         instance = Instance implementation object.
735         
736     Returns:
737         Returns a structure with the event fields that it could detect.
738     +/
739     InstanceEvents getInstanceEvents(T)(T instance) @trusted
740     if (isInstance!T)
741     {
742         import std.algorithm : canFind, remove;
743         import std.traits : getUDAs, TemplateArgsOf, Parameters;
744 
745         InstanceEvents events;
746 
747         events.IInitFunctions = [];
748         events.IStepFunctions = [];
749         events.IEntryFunctions = [];
750         events.IRestartFunctions = [];
751         events.ILeaveFunctions = [];
752         events.IGameStartFunctions = [];
753         events.IGameExitFunctions = [];
754         events.IGameRestartFunctions = [];
755         events.IEventHandleFunctions = [];
756         events.IDrawFunctions = [];
757         events.IOnErrorFunctions = [];
758         events.IColliderStructs = [];
759         events.IOnTriggerFunctions = [];
760         events.IOnDestroyFunctions = [];
761         events.ICollisionFunctions = [];
762         events.IOnAnyTriggerFunctions = [];
763         events.IStepThreadFunctions = [0:null];
764 
765         void delegate() @safe[]* minStepTh;
766         size_t minStepLen;
767 
768         static foreach (member; __traits(allMembers, T))
769         {
770             static if (hasAttrib!(T, tida.localevent.event, member))
771             {
772                 static if (attributeIn!(T, event, member).type == Init)
773                 {
774                     static if (getUDAs!(__traits(getMember, instance, member), args).length != 0)
775                     {
776                         events.IInitFunctions ~= InstanceEvents.FEEntry.create!(
777                             getUDAs!(__traits(getMember, instance, member), args)[0].members
778                         )(cast(void delegate() @safe) &__traits(getMember, instance, member));
779                     } else
780                     {
781                         static assert (
782                             Parameters!(__traits(getMember, instance, member)).length == 0,
783                             "An initialization event cannot have any arguments. To do this, add an attribute `@args!(params...)`"
784                         );
785 
786                         events.IInitFunctions ~= InstanceEvents.FEEntry.create(cast(void delegate() @safe) &__traits(getMember, instance, member));
787                     }
788                 } else
789                 static if (attributeIn!(T, event, member).type == Restart)
790                 {
791                     static if (getUDAs!(__traits(getMember, instance, member), args).length != 0)
792                     {
793                         events.IRestartFunctions ~= InstanceEvents.FEEntry.create!(
794                             getUDAs!(__traits(getMember, instance, member), args)[0].members
795                         )(cast(void delegate() @safe) &__traits(getMember, instance, member));
796                     } else
797                     {
798                         static assert (
799                             Parameters!(__traits(getMember, instance, member)).length == 0,
800                             "An restart event cannot have any arguments. To do this, add an attribute `@args!(params...)`"
801                         );
802 
803                         events.IRestartFunctions ~= InstanceEvents.FEEntry.create(cast(void delegate() @safe) &__traits(getMember, instance, member));
804                     }
805                 } else
806                 static if (attributeIn!(T, event, member).type == Entry)
807                 {
808                     static if (getUDAs!(__traits(getMember, instance, member), args).length != 0)
809                     {
810                         events.IEntryFunctions ~= InstanceEvents.FEEntry.create!(
811                             getUDAs!(__traits(getMember, instance, member), args)[0].members
812                         )(cast(void delegate() @safe) &__traits(getMember, instance, member));
813                     } else
814                     {
815                         static assert (
816                             Parameters!(__traits(getMember, instance, member)).length == 0,
817                             "An entry event cannot have any arguments. To do this, add an attribute `@args!(params...)`"
818                         );
819 
820                         events.IEntryFunctions ~= InstanceEvents.FEEntry.create(cast(void delegate() @safe) &__traits(getMember, instance, member));
821                     }
822                 } else
823                 static if (attributeIn!(T, event, member).type == Leave)
824                 {
825                     events.ILeaveFunctions ~= &__traits(getMember, instance, member);
826                 } else
827                 static if (attributeIn!(T, event, member).type == Step)
828                 {
829                     events.IStepFunctions ~= &__traits(getMember, instance, member);
830                 } else
831                 static if (attributeIn!(T, event, member).type == GameStart)
832                 {
833                     events.IGameStartFunctions ~= &__traits(getMember, instance, member);
834                 } else
835                 static if (attributeIn!(T, event, member).type == GameExit)
836                 {
837                     events.IGameExitFunctions ~= &__traits(getMember, instance, member);
838                 } else
839                 static if (attributeIn!(T, event, member).type == GameRestart)
840                 {
841                     events.IGameRestartFunctions ~= &__traits(getMember, instance, member);
842                 } else
843                 static if (attributeIn!(T, event, member).type == Input)
844                 {
845                     events.IEventHandleFunctions ~= &__traits(getMember, instance, member);
846                 } else
847                 static if (attributeIn!(T, event, member).type == Draw)
848                 {
849                     events.IDrawFunctions ~= &__traits(getMember, instance, member);
850                 } else
851                 static if (attributeIn!(T, event, member).type == AnyTrigger)
852                 {
853                     events.IOnAnyTriggerFunctions ~= &__traits(getMember, instance, member);
854                 } else
855                 static if (attributeIn!(T, event, member).type == AnyCollision)
856                 {
857                     events.ICollisionFunctions ~= &__traits(getMember, instance, member);
858                 } else
859                 static if (attributeIn!(T, event, member).type == Destroy)
860                 {
861                     events.IOnDestroyFunctions ~= &__traits(getMember, instance, member);
862                 } else
863                 static if (attributeIn!(T, event, member).type == GameError)
864                 {
865                     events.IOnErrorFunctions ~= &__traits(getMember, instance, member);
866                 }
867             } else
868             static if (hasAttrib!(T, Trigger, member))
869             {
870                 events.IOnTriggerFunctions ~= InstanceEvents.SRTrigger (attributeIn!(T, Trigger, member),
871                                                         &__traits(getMember, instance, member));
872             } else
873             static if (hasAttrib!(T, StepThread, member))
874             {
875                 events.IStepThreadFunctions
876                 [attributeIn!(T, StepThread, member).id] ~= &__traits(getMember, instance, member);
877 
878                 if (countStartThreads < attributeIn!(T, StepThread, member).id)
879                 {
880                     countStartThreads = attributeIn!(T, StepThread, member).id;
881                 }
882             } else
883             static if (hasAttrib!(T, Collision, member))
884             {
885                 events.IColliderStructs ~= InstanceEvents.SRCollider(attributeIn!(T, Collision, member),
886                                                          &__traits(getMember, instance, member));
887             }else
888             static if (hasAttrib!(T, stepThreadSafe, member))
889             {
890                 import std.algorithm : maxElement;
891 
892                 if (events.IStepThreadFunctions.length != 1)
893                 {       
894                     minStepLen = events.IStepThreadFunctions.values.maxElement!(a => a.length).length;
895                     foreach (key, value; events.IStepThreadFunctions)
896                     {
897                         if (value.length < minStepLen)
898                         {
899                             minStepTh = &events.IStepThreadFunctions[key];
900                             minStepLen = value.length;
901                         }
902                     }
903                 } else
904                 {
905                     foreach (i; 1 .. maxThreads + 1)
906                         events.IStepThreadFunctions[i] = [];
907                         
908                     minStepTh = &events.IStepThreadFunctions[maxThreads];
909                     minStepLen = events.IStepThreadFunctions[maxThreads].length;
910                 }
911             
912                 if (minStepLen > functionPerThread)
913                 {
914                     events.IStepFunctions ~= &__traits(getMember, instance, member);
915                 }
916                 else
917                 {
918                     *minStepTh ~= &__traits(getMember, instance, member);
919                 }
920             }
921         }
922 
923         return events;
924     }
925 
926     ComponentEvents getComponentEvents(T)(Instance instance, T component) @safe
927     {
928         ComponentEvents events;
929 
930         events.CStepFunctions = [];
931         events.CLeaveFunctions = [];
932         events.CEventHandleFunctions = [];
933         events.CDrawFunctions = [];
934         events.COnErrorFunctions = [];
935         events.COnTriggerFunctions = [];
936         events.COnAnyTriggerFunctions = [];
937 
938         static foreach (member; __traits(allMembers, T))
939         {
940             static if (hasAttrib!(T, tida.localevent.event, member))
941             {
942                 static if (attributeIn!(T, event, member).type == Init)
943                 {
944                     events.CInitFunctions ~= ComponentEvents.FEInit(
945                         instance,
946                         &__traits(getMember, component, member)
947                     );
948                 } else
949                 static if (attributeIn!(T, event, member).type == Leave)
950                 {
951                     events.CLeaveFunctions ~= &__traits(getMember, component, member);
952                 } else
953                 static if (attributeIn!(T, event, member).type == Step)
954                 {
955                     events.CStepFunctions ~= &__traits(getMember, component, member);
956                 } else
957                 static if (attributeIn!(T, event, member).type == Input)
958                 {
959                     events.CEventHandleFunctions ~= &__traits(getMember, component, member);
960                 } else
961                 static if (attributeIn!(T, event, member).type == Draw)
962                 {
963                     events.CDrawFunctions ~= &__traits(getMember, component, member);
964                 } else
965                 static if (attributeIn!(T, event, member).type == AnyTrigger)
966                 {
967                     events.COnAnyTriggerFunctions ~= &__traits(getMember, component, member);
968                 } else
969                 static if (attributeIn!(T, event, member).type == AnyCollision)
970                 {
971                     events.COnAnyCollisionFunctions ~= &__traits(getMember, component, member);
972                 } else
973                 static if (attributeIn!(T, event, member).type == GameError)
974                 {
975                     events.COnErrorFunctions ~= &__traits(getMember, component, member);
976                 }
977             } else
978             static if (hasAttrib!(T, Trigger, member))
979             {
980                 events.COnTriggerFunctions ~= ComponentEvents.SRTrigger (attributeIn!(T, Trigger, member),
981                                                         &__traits(getMember, component, member));
982             }
983         }
984 
985         return events;
986     }
987 
988     SceneEvents getSceneEvents(T)(T scene) @trusted
989     {
990         import std.traits : hasUDA, getUDAs, TemplateArgsOf, Parameters;
991 
992         SceneEvents events;
993 
994         events.InitFunctions = [];
995         events.StepFunctions = [];
996         events.EntryFunctions = [];
997         events.RestartFunctions = [];
998         events.LeaveFunctions = [];
999         events.GameStartFunctions = [];
1000         events.GameExitFunctions = [];
1001         events.GameRestartFunctions = [];
1002         events.EventHandleFunctions = [];
1003         events.DrawFunctions = [];
1004         events.OnErrorFunctions = [];
1005         events.OnTriggerFunctions = [];
1006         events.OnDestroyFunctions = [];
1007         events.StepThreadFunctions = [0:null];
1008 
1009         void delegate() @safe[]* minStepTh;
1010         size_t minStepLen;
1011 
1012         static foreach (member; __traits(allMembers, T))
1013         {
1014             static if (hasAttrib!(T, tida.localevent.event, member))
1015             {
1016                 static if (attributeIn!(T, event, member).type == Init)
1017                 {
1018                     static if (getUDAs!(__traits(getMember, scene, member), args).length != 0)
1019                     {
1020                         events.InitFunctions ~= SceneEvents.FEEntry.create!(
1021                             getUDAs!(__traits(getMember, scene, member), args)[0].members
1022                         )(cast(void delegate() @safe) &__traits(getMember, scene, member));
1023                     } else
1024                     {
1025                         static assert (
1026                             Parameters!(__traits(getMember, scene, member)).length == 0,
1027                             "An initialization event cannot have any arguments. To do this, add an attribute `@args!(params...)`"
1028                         );
1029 
1030                         events.InitFunctions ~= SceneEvents.FEEntry.create(cast(void delegate() @safe) &__traits(getMember, scene, member));
1031                     }
1032                 } else
1033                 static if (attributeIn!(T, event, member).type == Restart)
1034                 {
1035                     static if (getUDAs!(__traits(getMember, scene, member), args).length != 0)
1036                     {
1037                         events.RestartFunctions ~= SceneEvents.FEEntry.create!(
1038                             getUDAs!(__traits(getMember, scene, member), args)[0].members
1039                         )(cast(void delegate() @safe) &__traits(getMember, scene, member));
1040                     } else
1041                     {
1042                         static assert (
1043                             Parameters!(__traits(getMember, scene, member)).length == 0,
1044                             "An restart event cannot have any arguments. To do this, add an attribute `@args!(params...)`"
1045                         );
1046 
1047                         events.RestartFunctions ~= SceneEvents.FEEntry.create(&__traits(getMember, scene, member));
1048                     }
1049                 } else
1050                 static if (attributeIn!(T, event, member).type == Entry)
1051                 {
1052                     static if (getUDAs!(__traits(getMember, scene, member), args).length != 0)
1053                     {
1054                         events.EntryFunctions ~= SceneEvents.FEEntry.create!(
1055                             getUDAs!(__traits(getMember, scene, member), args)[0].members
1056                         )(cast(void delegate() @safe) &__traits(getMember, scene, member));
1057                     } else
1058                     {
1059                         static assert (
1060                             Parameters!(__traits(getMember, scene, member)).length == 0,
1061                             "An entry event cannot have any arguments. To do this, add an attribute `@args!(params...)`"
1062                         );
1063 
1064                         events.EntryFunctions ~= SceneEvents.FEEntry.create(&__traits(getMember, scene, member));
1065                     }
1066                 } else
1067                 static if (attributeIn!(T, event, member).type == Leave)
1068                 {
1069                     events.LeaveFunctions ~= &__traits(getMember, scene, member);
1070                 } else
1071                 static if (attributeIn!(T, event, member).type == Step)
1072                 {
1073                     events.StepFunctions ~= &__traits(getMember, scene, member);
1074                 } else
1075                 static if (attributeIn!(T, event, member).type == GameStart)
1076                 {
1077                     events.GameStartFunctions ~= &__traits(getMember, scene, member);
1078                 } else
1079                 static if (attributeIn!(T, event, member).type == GameExit)
1080                 {
1081                     events.GameExitFunctions ~= &__traits(getMember, scene, member);
1082                 } else
1083                 static if (attributeIn!(T, event, member).type == GameRestart)
1084                 {
1085                     events.GameRestartFunctions ~= &__traits(getMember, scene, member);
1086                 } else
1087                 static if (attributeIn!(T, event, member).type == Input)
1088                 {
1089                     events.EventHandleFunctions ~= &__traits(getMember, scene, member);
1090                 } else
1091                 static if (attributeIn!(T, event, member).type == Draw)
1092                 {
1093                     events.DrawFunctions ~= &__traits(getMember, scene, member);
1094                 } else
1095                 static if (attributeIn!(T, event, member).type == AnyTrigger)
1096                 {
1097                     events.OnAnyTriggerFunctions ~= &__traits(getMember, scene, member);
1098                 } else
1099                 static if (attributeIn!(T, event, member).type == AnyCollision)
1100                 {
1101                     events.OnAnyCollisionFunctions ~= &__traits(getMember, scene, member);
1102                 } else
1103                 static if (attributeIn!(T, event, member).type == Destroy)
1104                 {
1105                     events.OnDestroyFunctions ~= &__traits(getMember, scene, member);
1106                 } else
1107                 static if (attributeIn!(T, event, member).type == GameError)
1108                 {
1109                     events.OnErrorFunctions ~= &__traits(getMember, scene, member);
1110                 }
1111             } else
1112             static if (hasAttrib!(T, Trigger, member))
1113             {
1114                 events.OnTriggerFunctions ~= SceneEvents.SRTrigger (attributeIn!(T, Trigger, member),
1115                                                         &__traits(getMember, scene, member));
1116             } else
1117             static if (hasAttrib!(T, StepThread, member))
1118             {
1119                 events.StepThreadFunctions
1120                 [attributeIn!(T, StepThread, member).id] ~= &__traits(getMember, scene, member);
1121 
1122                 if (countStartThreads < attributeIn!(T, StepThread, member).id)
1123                 {
1124                     countStartThreads = attributeIn!(T, StepThread, member).id;
1125                 }
1126             } else
1127             static if (hasAttrib!(T, stepThreadSafe, member))
1128             {
1129                 import std.algorithm : maxElement;
1130 
1131                 if (events.StepThreadFunctions.length != 1)
1132                 {
1133                     minStepLen = events.StepThreadFunctions.values.maxElement!(a => a.length).length;
1134                     foreach (key, value; events.StepThreadFunctions)
1135                     {
1136                         if (value.length < minStepLen)
1137                         {
1138                             minStepTh = &events.StepThreadFunctions[key];
1139                             minStepLen = value.length;
1140                         }
1141                     }
1142                 } else
1143                 {
1144                     foreach (i; 1 .. maxThreads + 1)
1145                         events.StepThreadFunctions[i] = [];
1146 
1147                     minStepTh = &events.StepThreadFunctions[maxThreads];
1148                     minStepLen = events.StepThreadFunctions[maxThreads].length;
1149                 }
1150 
1151                 if (minStepLen > functionPerThread)
1152                 {
1153                     events.StepFunctions ~= &__traits(getMember, scene, member);
1154                 }
1155                 else
1156                 {
1157                     *minStepTh ~= &__traits(getMember, scene, member);
1158                 }
1159             }
1160         }
1161 
1162         return events;
1163     }
1164 
1165     unittest
1166     {
1167         initSceneManager();
1168 
1169         static class A : Instance
1170         {
1171             @event(AnyTrigger)
1172             void onInit(string member) @safe { }
1173 
1174             @event(Draw)
1175             void onDraw(IRenderer render) @safe { }
1176         }
1177 
1178         A a = new A();
1179         InstanceEvents evs = sceneManager.getInstanceEvents(a);
1180 
1181         assert (evs.IOnAnyTriggerFunctions[0] == &a.onInit);
1182         assert (evs.IDrawFunctions[0] == &a.onDraw);
1183     }
1184 
1185     /++
1186     Raise the event of destruction of the instance. (@FunEvent!Destroy)
1187 
1188     Params:
1189         instance = Instance.
1190     +/
1191     void destroyEventCall(T)(T instance) @trusted
1192     if (isInstance!T)
1193     {
1194         foreach(func; instance.events.IOnDestroyFunctions)
1195             func(instance);
1196     }
1197 
1198     /++
1199     Reise the event of destruction in current scene. (@FunEvent!Destroy)
1200 
1201     Params:
1202         scene = Current scene.
1203         instance = Instance.
1204     +/
1205     void destroyEventSceneCall(T, R)(T scene, R instance) @trusted
1206     {
1207         static assert(isScene!T, "`" ~ T.stringof ~ "` is not a scene!");
1208         static assert(isInstance!R, "`" ~ R.stringof ~ "` is not a instance!");
1209 
1210         foreach(func; scene.events.OnDestroyFunctions) func(instance);
1211     }
1212 
1213     package(tida) void componentExplore(T)(Instance instance, T component) @trusted
1214     if (isComponent!T)
1215     {
1216         component.events = getComponentEvents!T(instance, component);
1217 
1218         foreach (fun; component.events.CInitFunctions)
1219             fun.fun (fun.instance);
1220     }
1221 
1222     private void exploreScene(T)(T scene) @trusted
1223     {
1224         scene.events = getSceneEvents!T(scene);
1225     }
1226 
1227     package(tida) void instanceExplore(T)(Scene scene, T instance) @trusted
1228     if (isInstance!T)
1229     {
1230         if (instance.events == InstanceEvents.init)
1231             instance.events = getInstanceEvents!T(instance);
1232     }
1233 
1234     package(tida) void removeHandle(Scene scene, Instance instance) @trusted
1235     {
1236         // TODO: Implement this
1237     }
1238 
1239     /++
1240     Creates and adds a scene to the list.
1241 
1242     Params:
1243         T = Scene name.
1244 
1245     Example:
1246     ---
1247     sceneManager.add!MyScene;
1248     ---
1249     +/
1250     void add(T)() @trusted
1251     {
1252         auto scene = new T();
1253         if (scene.name == "")
1254             scene.name = T.stringof;
1255 
1256         add!T(scene);
1257     }
1258 
1259     void remove(T)(T scene) @trusted
1260     {
1261         scenes.remove(scene.name);
1262         destroy(scene);
1263     }
1264 
1265     void remove(T)() @trusted
1266     {
1267         static assert(isScene!T, "`" ~ T.stringof ~ "` is not a scene!");
1268 
1269         foreach(scene; scenes)
1270         {
1271             if((cast(T) scene) !is null)
1272             {
1273                 remove(scene);
1274                 return;
1275             }
1276         }
1277     }
1278 
1279     void remove(string name) @trusted
1280     {
1281         foreach(scene; scenes)
1282         {
1283             if(scene.name == name)
1284             {
1285                 remove(scene);
1286                 return;
1287             }
1288         }
1289     }
1290 
1291     public
1292     {
1293         /++
1294         Array of requests. At each stroke of the cycle, it is checked,
1295         processed and cleaned. If an error occurs during the request,
1296         they are added to `apiError`.
1297         +/
1298         APIResponse[] api;
1299         
1300         /++
1301         An array of pre-known commands to execute without chasing data for each thread.
1302         +/
1303         APIResponse[][size_t] threadAPI;
1304 
1305         /++
1306         An array of request errors associated with the request type.
1307         +/
1308         uint[uint] apiError;
1309     }
1310 
1311     /++
1312     Exits the game with a successful error code.
1313     +/
1314     void close(int code = 0) @safe
1315     {
1316         api ~= APIResponse(APIType.GameClose, code);
1317     }
1318 
1319     /++
1320     Creates the specified count of anonymous threads.
1321 
1322     Params:
1323         count = Count anonymous threads.
1324     +/
1325     void initThread(uint count = 1) @safe
1326     {
1327         api ~= APIResponse(APIType.ThreadCreate, count);
1328     }
1329 
1330     /++
1331     Pauses said thread.
1332 
1333     Params:
1334         value = Thread identificator.
1335     +/
1336     void pauseThread(uint value) @safe
1337     {
1338         api ~= APIResponse(APIType.ThreadPause, value);
1339     }
1340 
1341     /++
1342     Resumes said thread.
1343 
1344     Params:
1345         value = Thread identificator.
1346     +/
1347     void resumeThread(uint value) @safe
1348     {
1349         api ~= APIResponse(APIType.ThreadResume, value);
1350     }
1351 
1352     void stopThread(uint value) @safe
1353     {
1354         api ~= APIResponse(APIType.ThreadClose, value);
1355     }
1356 
1357     /++
1358     Goes to the first scene added.
1359     +/
1360     void inbegin() @safe
1361     {
1362         gotoin(_ofbegin);
1363     }
1364 
1365     /++
1366     Goes to the scene by its string name.
1367 
1368     Params:
1369         name = Scene name.
1370     +/
1371     void gotoin(T...)(string name, T args)
1372     {
1373         import std.algorithm : remove;
1374 
1375         foreach (inscene; scenes)
1376         {
1377             if(inscene.name == name)
1378             {
1379                 gotoin(inscene, args);
1380                 break;
1381             }
1382         }
1383         
1384         foreach (key, value; lazySpawns)
1385         {
1386             if (key == name)
1387             {
1388                 auto scene = value();
1389                 lazySpawns.remove(key);
1390                 gotoin(scene, args);
1391                 return;
1392             }
1393         }
1394 
1395         foreach (i; 0 .. lazyGroupSpawns.length)
1396         {
1397             auto e = lazyGroupSpawns[i];
1398 
1399             if (e.names.canFind(name))
1400             {
1401                 lazyGroupSpawns = remove(lazyGroupSpawns, i);
1402                 auto lazyScenes = e.spawnFunction();
1403                 gotoin(lazyScenes[name], args);
1404                 return;
1405             }
1406         }
1407     }
1408 
1409     /++
1410     Goes to the scene by its class.
1411 
1412     Params:
1413         Name = Scene.
1414     +/
1415     void gotoin(Name, T...)(T args)
1416     {
1417         import std.algorithm : remove;
1418 
1419         foreach (s; scenes)
1420         {
1421             if ((cast(Name) s) !is null)
1422             {
1423                 gotoin(s, args);
1424                 return;
1425             }
1426         }
1427 
1428         foreach (key, value; lazySpawns)
1429         {
1430             if (key == Name.stringof)
1431             {
1432                 auto scene = value();
1433                 lazySpawns.remove(key);
1434                 gotoin(scene, args);
1435                 return;
1436             }
1437         }
1438 
1439         foreach (i; 0 .. lazyGroupSpawns.length)
1440         {
1441             auto e = lazyGroupSpawns[i];
1442 
1443             if (e.names.canFind(Name.stringof))
1444             {
1445                 lazyGroupSpawns = remove(lazyGroupSpawns, i);
1446                 auto lazyScenes = e.spawnFunction();
1447                 gotoin(lazyScenes[Name.stringof], args);
1448                 return;
1449             }
1450         }
1451 
1452         throw new Exception("Not find this scene!");
1453     }
1454 
1455     /++
1456     Moves to the scene at the pointer.
1457 
1458     It is such a function that generates initialization events, entry,
1459     transferring the context to the scene and causing the corresponding
1460     events to lose the context.
1461 
1462     Params:
1463         scene = Scene heir.
1464     +/
1465     void gotoin(T...)(Scene scene, T args) @trusted
1466     {
1467         import tida.game : renderer, window;
1468         import tida.shape;
1469         import tida.vector;
1470     
1471         _previous = current;
1472         _thereGoto = true;
1473 
1474         if (current !is null)
1475         {
1476             foreach (fun; current.events.LeaveFunctions)
1477             {
1478                 fun();
1479             }
1480 
1481             foreach (instance; current.list())
1482             {
1483                 foreach (fun; instance.events.ILeaveFunctions)
1484                 {
1485                     fun();
1486                 }
1487             }
1488         }
1489 
1490         if (current !is null)
1491         {
1492             Instance[] persistents;
1493 
1494             foreach (instance; _previous.list())
1495             {
1496                 if (instance.persistent)
1497                     persistents ~= instance;
1498             }
1499 
1500             foreach (e; persistents)
1501             {
1502                 auto threadID = e.threadid;
1503                 current.instanceDestroy!InScene(e, false);
1504 
1505                 if (scene.isThreadExists(threadID))
1506                     scene.add(e, threadID);
1507                 else
1508                     scene.add(e);
1509             }
1510         }
1511 
1512         _initable = scene;
1513 
1514         if (!scene.isInit)
1515         {
1516             foreach (fun; scene.events.InitFunctions)
1517             {
1518                 fun(args);
1519             }
1520 
1521             foreach (instance; scene.list())
1522             {
1523                 foreach (fun; instance.events.IInitFunctions)
1524                 {
1525                     fun(args);
1526                 }
1527             }
1528 
1529             scene.isInit = true;
1530         }else
1531         {
1532             foreach (fun; scene.events.RestartFunctions)
1533             {
1534                 fun(args);
1535             }
1536 
1537             foreach (instance; scene.list())
1538             {
1539                 foreach (fun; instance.events.IRestartFunctions)
1540                 {
1541                     fun(args);
1542                 }
1543             }
1544         }
1545 
1546         foreach(fun; scene.events.EntryFunctions)
1547         {
1548             fun(args);
1549         }
1550 
1551         foreach (instance; scene.list())
1552         {
1553             foreach (fun; instance.events.IEntryFunctions)
1554             {
1555                 fun(args);
1556             }
1557         }
1558 
1559         _initable = null;
1560 
1561         _current = scene;
1562 
1563         version (unittest)
1564         {
1565             // avoid
1566         } else
1567         {
1568             if (scene.camera !is null)
1569             {
1570                 renderer.camera = scene.camera;
1571             }
1572             else
1573             {
1574                 renderer.camera = defaultCamera();
1575             }
1576         }
1577 
1578         _thereGoto = false;
1579     }
1580 
1581     /++
1582     Calling the game launch event.
1583 
1584     Should be called before all events, before the beginning of the
1585     cycle of life.
1586     +/
1587     void callGameStart() @trusted
1588     {
1589         foreach (scene; scenes)
1590         {
1591             foreach (fun; scene.events.GameStartFunctions)
1592             {
1593                 fun();
1594             }
1595 
1596             foreach (instance; scene.list())
1597             {
1598                 if (instance.active && !instance.onlyDraw)
1599                 {
1600                     foreach (fun; instance.events.IGameStartFunctions)
1601                     {
1602                         fun();
1603                     }
1604                 }
1605             }
1606         }
1607     }
1608 
1609     /++
1610     Game completion call events (successful).
1611     The unsuccessful event should raise the `onError` event.
1612     +/
1613     void callGameExit() @trusted
1614     {
1615         foreach (scene; scenes)
1616         {
1617             foreach (fun; scene.events.GameExitFunctions)
1618             {
1619                 fun();
1620             }
1621 
1622             foreach (instance; scene.list())
1623             {
1624                 if (instance.active && !instance.onlyDraw)
1625                 {
1626                     foreach (fun; instance.events.IGameExitFunctions)
1627                     {
1628                         fun();
1629                     }
1630                 }
1631             }
1632         }
1633     }
1634 
1635     unittest
1636     {
1637         initSceneManager();
1638 
1639         static class Test : Scene
1640         {
1641             int trigger = int.init;
1642 
1643             this() @safe
1644             {
1645                 name = "Test";
1646             }
1647         }
1648 
1649         sceneManager.add (new Test());
1650 
1651         sceneManager.gotoin("Test");
1652 
1653         assert ((cast (Test) sceneManager.scenes["Test"]).trigger == 0);
1654         (cast (Test) sceneManager.scenes["Test"]).trigger = 32;
1655         assert ((cast (Test) sceneManager.scenes["Test"]).trigger == 32);
1656 
1657         sceneManager.gameRestart();
1658 
1659         assert ((cast (Test) sceneManager.scenes["Test"]).trigger == 0);
1660     }
1661 
1662     /++
1663     Triggering an emergency event.
1664 
1665     Does not terminate the game, should be called on exceptions. After that,
1666     the programmer himself decides what to do next (if he implements his own
1667     life cycle). Called usually on `scope (failure)`, however, it will not
1668     throw a specific exception.
1669     +/
1670     void callOnError() @trusted
1671     {
1672         if (current !is null)
1673         {
1674             foreach (fun; current.events.OnErrorFunctions)
1675             {
1676                 fun();
1677             }
1678 
1679             foreach (instance; current.list())
1680             {
1681                 if (instance.active && !instance.onlyDraw)
1682                 {
1683                     foreach (fun; instance.events.IOnErrorFunctions)
1684                     {
1685                         fun();
1686                     }
1687                 }
1688             }
1689         }
1690     }
1691 
1692     /++
1693     Calling a game step. Should always be called during a loop step in an
1694     exception when the thread is suspended.
1695 
1696     Params:
1697         thread = Thread identificator.
1698         rend   = Renderer instance.
1699     +/
1700     void callStep(size_t thread, IRenderer rend) @trusted
1701     {
1702         if (current !is null)
1703         {
1704             if (thread == 0)
1705             {
1706                 current.worldCollision();
1707             
1708                 if (current.camera !is null)
1709                     current.camera.followObject();
1710 
1711                 foreach (fun; current.events.StepFunctions)
1712                 {
1713                     fun();
1714                 }
1715             }
1716 
1717             if (thread in current.events.StepThreadFunctions)
1718             {
1719                 foreach (fun; current.events.StepThreadFunctions[thread])
1720                     fun();
1721             }
1722 
1723             foreach (instance; current.getThreadList(thread))
1724             {
1725                 if (instance.isDestroy)
1726                 {
1727                     current.instanceDestroy!InMemory(instance);
1728                     current.sort();
1729                     continue;
1730                 }
1731 
1732                 if (!instance.active || instance.onlyDraw) continue;
1733 
1734                 foreach (fun; instance.events.IStepFunctions)
1735                 {
1736                     fun();
1737                 }
1738 
1739                 foreach (component; instance.getComponents())
1740                 {
1741                     foreach (fun; component.events.CStepFunctions)
1742                     {
1743                         fun();
1744                     }
1745                 }
1746             }
1747 
1748             foreach(instance; current.list())
1749             {
1750                 if (!instance.active || instance.onlyDraw) 
1751                     continue;
1752 
1753                 if (thread in instance.events.IStepThreadFunctions)
1754                 {
1755                     foreach (fun; instance.events.IStepThreadFunctions[thread])
1756                         fun();
1757                 }
1758 
1759                 foreach (component; instance.getComponents())
1760                 {
1761                     if (thread in component.events.CStepThreadFunctions)
1762                     {
1763                         foreach(fun; component.events.CStepThreadFunctions[thread])
1764                         {
1765                             fun();
1766                         }
1767                     }
1768                 }
1769             }
1770         }
1771     }
1772 
1773     /++
1774     System event event for scenes and instances of the current context.
1775 
1776     Params:
1777         event = System event handler instance.
1778     +/
1779     void callEvent(EventHandler event) @trusted
1780     {
1781         if (current !is null)
1782         {
1783             foreach (fun; current.events.EventHandleFunctions)
1784             {
1785                 fun(event);
1786             }
1787 
1788             foreach (instance; current.list())
1789             {
1790                 if (instance.active && !instance.onlyDraw)
1791                 {
1792                     foreach(fun; instance.events.IEventHandleFunctions)
1793                     {
1794                         fun(event);
1795                     }
1796 
1797                     foreach (component; instance.getComponents())
1798                     {
1799                         foreach(fun; component.events.CEventHandleFunctions)
1800                         {
1801                             fun(event);
1802                         }
1803                     }
1804                 }
1805             }
1806         }
1807     }
1808 
1809     /++
1810     Calling an event to render scenes and instances of the current context.
1811 
1812     Params:
1813         render = Render instance.
1814     +/
1815     void callDraw(IRenderer render) @trusted
1816     {
1817         import tida.vector;
1818 
1819         if (current !is null)
1820         {
1821             foreach (fun; current.events.DrawFunctions)
1822             {
1823                 fun(render);
1824             }
1825 
1826             foreach (instance; current.getAssortedInstances())
1827             {
1828                 if (instance.active && instance.visible)
1829                 {
1830                     render.draw(instance.spriteDraw(), instance.position);
1831 
1832                     foreach (fun; instance.events.IDrawFunctions)
1833                     {
1834                         fun(render);
1835                     }
1836 
1837                     foreach (component; instance.getComponents())
1838                     {
1839                         foreach (fun; component.events.CDrawFunctions)
1840                         {
1841                             fun(render);
1842                         }
1843                     }
1844                 }
1845             }
1846         }
1847     }
1848 
1849     /// Free memory.
1850     void free() @safe
1851     {
1852         _scenes = null;
1853     }
1854 
1855     ~this() @safe
1856     {
1857         free();
1858     }
1859 }
1860 
1861 unittest
1862 {
1863     initSceneManager();
1864 
1865     static class A : Scene
1866     {
1867         this() @safe
1868         {
1869             name = "Test";
1870         }
1871     }
1872 
1873     sceneManager.add(new A());
1874     assert(("Test" in sceneManager.scenes) !is null);
1875 }
1876 
1877 unittest
1878 {
1879     initSceneManager();
1880 
1881     static class A : Scene
1882     {
1883         @event(Init)
1884         void onInit() @safe { }
1885     }
1886 
1887     A obj = new A();
1888     sceneManager.add(obj);
1889 
1890     assert((obj.events.InitFunctions[0].func.ptr) == ((&obj.onInit).ptr));
1891 }
1892 
1893 unittest
1894 {
1895     initSceneManager();
1896 
1897     static class A : Scene
1898     {
1899         this() @safe
1900         {
1901             name = "Test";
1902         }
1903     }
1904 
1905     sceneManager.add(new A());
1906     assert(sceneManager.hasScene("Test"));
1907 }
1908 
1909 unittest
1910 {
1911     initSceneManager();
1912 
1913     struct Data
1914     {
1915         int first;
1916         string second;
1917     }
1918 
1919     static class A : Scene
1920     {
1921         bool state = false;
1922 
1923         this() @safe
1924         {
1925             name = "A";
1926         }
1927 
1928         @event(Entry) void onEntry() @safe
1929         {
1930             state = true;
1931         }
1932     }
1933 
1934     static class B : Scene
1935     {
1936         int first;
1937         Data second;
1938 
1939         this() @safe
1940         {
1941             name = "B";
1942         }
1943 
1944         @args!(int, Data)
1945         @event(Init) void onInit(int first, Data second) @safe
1946         {
1947             this.first = first;
1948             this.second = second;
1949         }
1950     }
1951 
1952     A a;
1953     B b;
1954 
1955     sceneManager.add (a = new A());
1956     sceneManager.add (b = new B());
1957 
1958     sceneManager.gotoin ("A");
1959     assert (a.state == true);
1960 
1961     sceneManager.gotoin ("B", 7, Data(9, "test"));
1962     assert (b.first == 7 && b.second == Data(9, "test"));
1963 }
1964 
1965 unittest
1966 {
1967     initSceneManager();
1968 
1969     struct Data
1970     {
1971         int first;
1972         string second;
1973     }
1974 
1975     static class A : Scene
1976     {
1977         bool state = false;
1978 
1979         this() @safe
1980         {
1981             name = "A";
1982         }
1983 
1984         @event(Entry) void onEntry() @safe
1985         {
1986             state = true;
1987         }
1988     }
1989 
1990     static class B : Scene
1991     {
1992         int first;
1993         Data second;
1994 
1995         this() @safe
1996         {
1997             name = "B";
1998         }
1999 
2000         @args!(int, Data)
2001         @event(Init) void onInit(int first, Data second) @safe
2002         {
2003             this.first = first;
2004             this.second = second;
2005         }
2006     }
2007 
2008     static class C : Instance
2009     {
2010         Data data;
2011 
2012         this() @safe
2013         {
2014             name = "C";
2015         }
2016 
2017         @args!(int, Data)
2018         @event(Init) void onInit(int first, Data second) @safe
2019         {
2020             this.data = second;
2021         }
2022     }
2023 
2024     A a;
2025     B b;
2026     C c;
2027 
2028     sceneManager.add (a = new A());
2029     sceneManager.add (b = new B());
2030 
2031     b.add (c = new C());
2032 
2033     sceneManager.gotoin ("A");
2034 
2035     sceneManager.gotoin ("B", 7, Data(9, "test"));
2036     assert (c.data == Data(9, "test"));
2037 }