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.event;
20 import tida.fps;
21 import core.thread;
22 
23 /++
24 Mistakes of using communication between the manager and the game cycle.
25 +/
26 enum APIError : uint
27 {
28     succes, /// Errors are not detected.
29     ThreadIsNotExists /// The stream with which it was necessary to interact - does not exist.
30 }
31 
32 /++
33 Commands that should execute the game cycle.
34 +/
35 enum APIType : uint
36 {
37     None, /// None
38     ThreadCreate, /// Create the specified number of threads.
39     ThreadPause,
40     ThreadResume,
41     ThreadClose,
42     GameClose
43 }
44 
45 /++
46 Container to send a message to the game cycle.
47 +/
48 struct APIResponse
49 {
50     uint code; /// Command thah should execute the game cycle.
51     uint value; /// Value response
52 }
53 
54 /++
55 Thread for execution of steps for scenes and instances.
56 +/
57 class InstanceThread : Thread
58 {
59 private:
60     bool isJob = true;
61     bool isPause = false;
62     FPSManager fps;
63     Instance[] list;
64     size_t thread;
65     IRenderer rend;
66 
67     void run()
68     {
69         while (isJob)
70         {
71             if (isPause) continue;
72             fps.countDown();
73 
74             sceneManager.callStep(thread, rend);
75 
76             fps.control();
77         }
78     }
79 
80 public @safe:
81 
82     /++
83     Params:
84         thread =    Unique Identificator for Flow, namely, a place in the array for which it can
85                     contact such arrays for copies of the compliant ideal.
86         rend   =    Renderer instance.
87     +/
88     this(size_t thread,IRenderer rend)
89     {
90         fps = new FPSManager();
91 
92         this.thread = thread;
93         this.rend = rend;
94 
95         super(&run);
96     }
97 
98     /// Replaces the idle identifier.
99     void rebindThreadID(size_t newID)
100     {
101         thread = newID;
102     }
103 
104     /// Pause the work of the thread.
105     void pause()
106     {
107         isPause = true;
108     }
109 
110     /// Continues thread work.
111     void resume()
112     {
113         isPause = false;
114     }
115 
116     /// Completes the flow of the thread.
117     void exit()
118     {
119         isJob = false;
120     }
121 }
122 
123 __gshared SceneManager _sceneManager;
124 
125 /// Scene manager instance.
126 SceneManager sceneManager() @trusted
127 {
128     return _sceneManager;
129 }
130 
131 /// Allocates memory under the scene manager.
132 void initSceneManager() @trusted
133 {
134     _sceneManager = new SceneManager();
135 }
136 
137 /++
138 Class describing scene manager.
139 
140 Performs the functions of switching the context of the scenes, memorize
141 the list for subsequent circulation, the ability to execute elementary
142 events, give an instance access to the current scene or scene, which is
143 involved in the event.
144 
145 To transfer the context, use the `gotoin`. Learn the current scene - `current`.
146 previous - `previous` Contact precisely to the global object - `scenemanager`.
147 +/
148 final class SceneManager
149 {
150 private:
151     Scene[string] _scenes;
152     Scene _current;
153     Scene _previous;
154     Scene _ofbegin;
155     Scene _ofend;
156     Scene _initable;
157     Scene _restarted;
158 
159 public @safe:
160     /// List scenes
161     @property Scene[string] scenes() nothrow
162     {
163         return _scenes;
164     }
165 
166     /++
167     The first added scene.
168 
169     It can be overridden so that when the game
170     is restarted, the manager will jump to the
171     scene from this line:
172     ---
173     sceneManager.ofbegin = myScene;
174     sceneManager.gameRestart();
175     ---
176     +/
177     @property Scene ofbegin() nothrow
178     {
179         return _ofbegin;
180     }
181 
182     /++
183     The last added scene.
184     +/
185     @property Scene ofend() nothrow
186     {
187         return _ofend;
188     }
189 
190     /++
191     The previous scene that was active.
192     +/
193     @property Scene previous() nothrow
194     {
195         return _previous;
196     }
197 
198     /++
199     A scene that restarts at the moment.
200     +/
201     @property Scene restarted() nothrow
202     {
203         return _restarted;
204     }
205 
206     /++
207     Restarting the game.
208 
209     Please note that this does not affect memory,
210     the state of variables, etc., however, gives such a simulation,
211     therefore, create a corresponding event for resetting the state
212     when the game is restarted, if this is provided.
213     +/
214     void gameRestart() @trusted
215     {
216         foreach (scene; scenes)
217         {
218             if (!scene.isInit) continue;
219 
220             _restarted = scene;
221 
222             foreach (fun; GameRestartFunctions[scene]) fun();
223             foreach (instance; scene.list())
224                 foreach (fun; IGameRestartFunctions[instance]) fun();
225 
226             scene.isInit = false;
227 
228             _restarted = null;
229         }
230 
231         gotoin(ofbegin);
232     }
233 
234     /++
235     Link to the current scene.
236 
237     Please note that such a pointer is correct only in those events that
238     differ from `init`,` restart`, `leave`, they can not go at all on the
239     current one that you hoped. Example: In the initialization event, you
240     want access to the scene, which is initialized, but here you can make
241     a mistake - the pointer leads to the previous scene. You can access
242     the current through `sceneManager.initable`.
243 
244     See_Also:
245         tida.scene.manager.SceneManager.initable
246     +/
247     @property Scene current() nothrow
248     {
249         return _current;
250     }
251 
252     /++
253     The reference to the scene, which is undergoing context change
254     processing.
255 
256     The use of such a link is permissible only in context transmission
257     events, otherwise, it is possible to detect the scene leading nowhere.
258     +/
259     @property Scene initable() nothrow
260     {
261         return _initable;
262     }
263 
264     /++
265     The reference to the current stage, as if it is under initialization,
266     whether it is during a restart or without them.
267 
268     This link is selected depending on what is happening. If this is caused
269     during the change of context, it will lead exactly the scene that
270     receives the context. If the manager restarts the game, the link leads
271     to the scene, which is now restarting if there are no such events, then
272     the scene leads to the current working scene.
273 
274     Examples:
275     ---
276     @FunEvent!Init
277     void Initialization() @safe
278     {
279         assert(sceneManager.initable is sceneManager.context); // ok
280     }
281 
282     @FunEvent!Step
283     void Move() @safe
284     {
285         assert(sceneManager.current is sceneManager.context); // ok
286     }
287 
288     @FunEvent!GameRestart
289     void onGameRestart() @safe
290     {
291         assert(sceneManager.restarted is sceneManager.context); // ok
292     }
293     ---
294     +/
295     @property Scene context()
296     {
297         if (_initable is null)
298         {
299             if (_restarted is null)
300             {
301                 return _current;
302             } else
303                 return _restarted;
304         } else
305             return _initable;
306 
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         if (scene in OnTriggerFunctions)
333         {
334             foreach (fun; OnTriggerFunctions[scene])
335             {
336                 if (fun.ev.name == name)
337                 {
338                     fun.fun();
339                 }
340             }
341         }
342 
343         foreach (instance; scene.list())
344         {
345             if (instance in IOnTriggerFunctions)
346             {
347                 foreach (fun; IOnTriggerFunctions[instance])
348                 {
349                     if (fun.ev.name == name)
350                     {
351                         fun.fun();
352                     }
353                 }
354             }
355         }
356     }
357 
358     /++
359     Checks if the scene is in the scene list.
360 
361     Params:
362         scene = Scene.
363     +/
364     bool hasScene(Scene scene)
365     {
366         if (scene is null)
367             return false;
368 
369         foreach (inscene; scenes)
370         {
371             if (scene is inscene)
372                 return true;
373         }
374 
375         return false;
376     }
377 
378     /++
379     Checks for the existence of a scene by its original class.
380 
381     Params:
382         Name = Class name.
383     +/
384     bool hasScene(Name)()
385     {
386         static assert(isScene!Name, "`" ~ Name.stringof ~ "` is not a scene!");
387 
388         foreach (scene; scenes)
389         {
390             if ((cast(Name) scene) !is null)
391                 return true;
392         }
393 
394         return false;
395     }
396 
397     /++
398     Checks if there is a scene with the specified name.
399 
400     Params:
401         name = Scene name.
402     +/
403     bool hasScene(string name)
404     {
405         foreach (scene; scenes)
406         {
407             if (scene.name == name) return true;
408         }
409 
410         return false;
411     }
412 
413     /++
414     Adds a scene to the list.
415 
416     Params:
417         scene = Scene.
418     +/
419     void add(T)(T scene)
420     {
421         static assert(isScene!T, "`" ~ T.stringof ~ "` is not a scene!");
422         exploreScene!T(scene);
423 
424         if (_ofbegin is null)
425             _ofbegin = scene;
426 
427         _scenes[scene.name] = scene;
428     }
429 
430     package(tida)
431     {
432         import std.container, std.range, std.traits;
433         import tida.component : Component;
434 
435         alias FEInit = void delegate() @safe;
436         alias FEStep = void delegate() @safe;
437         alias FERestart = void delegate() @safe;
438         alias FEEntry = void delegate() @safe;
439         alias FELeave = void delegate() @safe;
440         alias FEGameStart = void delegate() @safe;
441         alias FEGameExit = void delegate() @safe;
442         alias FEGameRestart = void delegate() @safe;
443         alias FEEventHandle = void delegate(EventHandler) @safe;
444         alias FEDraw = void delegate(IRenderer) @safe;
445         alias FEOnError = void delegate() @safe;
446         alias FECollision = void delegate(Instance) @safe;
447         alias FETrigger = void delegate() @safe;
448         alias FEDestroy = void delegate(Instance) @safe;
449         alias FEATrigger = void delegate(string) @safe;
450 
451         alias FECInit = void delegate(Instance) @safe;
452 
453         struct SRCollider
454         {
455             Collision ev;
456             FECollision fun;
457         }
458 
459         struct SRTrigger
460         {
461             Trigger ev;
462             FETrigger fun;
463         }
464 
465         FEInit[][Scene] InitFunctions;
466         FEStep[][Scene] StepFunctions;
467         FEStep[][size_t][Scene] StepThreadFunctions;
468         FERestart[][Scene] RestartFunctions;
469         FEEntry[][Scene] EntryFunctions;
470         FELeave[][Scene] LeaveFunctions;
471         FEGameStart[][Scene] GameStartFunctions;
472         FEGameExit[][Scene] GameExitFunctions;
473         FEGameRestart[][Scene] GameRestartFunctions;
474         FEEventHandle[][Scene] EventHandleFunctions;
475         FEDraw[][Scene] DrawFunctions;
476         FEOnError[][Scene] OnErrorFunctions;
477         SRTrigger[][Scene] OnTriggerFunctions;
478         FEDestroy[][Scene] OnDestroyFunctions;
479         FEATrigger[][Scene] OnAnyTriggerFunctions;
480         FECollision[][Scene] OnAnyCollisionFunctions;
481 
482         FEInit[][Instance] IInitFunctions;
483         FEStep[][Instance] IStepFunctions;
484         FEStep[][size_t][Instance] IStepThreadFunctions;
485         FERestart[][Instance] IRestartFunctions;
486         FEEntry[][Instance] IEntryFunctions;
487         FELeave[][Instance] ILeaveFunctions;
488         FEGameStart[][Instance] IGameStartFunctions;
489         FEGameExit[][Instance] IGameExitFunctions;
490         FEGameRestart[][Instance] IGameRestartFunctions;
491         FEEventHandle[][Instance] IEventHandleFunctions;
492         FEDraw[][Instance] IDrawFunctions;
493         FEOnError[][Instance] IOnErrorFunctions;
494         SRCollider[][Instance] IColliderStructs;
495         FECollision[][Instance] ICollisionFunctions;
496         SRTrigger[][Instance] IOnTriggerFunctions;
497         FEDestroy[][Instance] IOnDestroyFunctions;
498         FEATrigger[][Instance] IOnAnyTriggerFunctions;
499 
500         FEStep[][Component] CStepFunctions;
501         FEStep[][size_t][Component] CStepThreadFunctions;
502         FELeave[][Component] CLeaveFunctions;
503         FEEventHandle[][Component] CEventHandleFunctions;
504         FEDraw[][Component] CDrawFunctions;
505         FEOnError[][Component] COnErrorFunctions;
506         SRTrigger[][Component] COnTriggerFunctions;
507     }
508 
509     /++
510     Raise the event of destruction of the instance. (@FunEvent!Destroy)
511 
512     Params:
513         instance = Instance.
514     +/
515     void destroyEventCall(T)(T instance) @trusted
516     {
517         static assert(isInstance!T, "`" ~ T.stringof ~ "` is not a instance!");
518         foreach(func; IOnDestroyFunctions[instance]) func(instance);
519     }
520 
521     /++
522     Reise the event of destruction in current scene. (@FunEvent!Destroy)
523 
524     Params:
525         scene = Current scene.
526         instance = Instance.
527     +/
528     void destroyEventSceneCall(T, R)(T scene, R instance) @trusted
529     {
530         static assert(isScene!T, "`" ~ T.stringof ~ "` is not a scene!");
531         static assert(isInstance!R, "`" ~ R.stringof ~ "` is not a instance!");
532 
533         foreach(func; OnDestroyFunctions[scene]) func(instance);
534     }
535 
536     package(tida) void componentExplore(T)(Instance instance, T component) @trusted
537     {
538         import tida.component : isComponent;
539 
540         static assert(isComponent!T, "`" ~ T.stringof ~ "` is not a component!");
541 
542         CStepFunctions[component] = [];
543         CLeaveFunctions[component] = [];
544         CEventHandleFunctions[component] = [];
545         CDrawFunctions[component] = [];
546         COnErrorFunctions[component] = [];
547         COnTriggerFunctions[component] = [];
548 
549         static foreach (member; __traits(allMembers, T))
550         {
551             static foreach (attrib; __traits(getAttributes, __traits(getMember, component, member)))
552             {
553                 static if (is(attrib : FunEvent!Init))
554                 {
555                     auto fun = cast(FECInit) &__traits(getMember, component, member);
556                     fun(instance);
557                 } else
558                 static if (is(attrib : FunEvent!Step))
559                 {
560                     CStepFunctions[component] ~= &__traits(getMember, component, member);
561                 } else
562                 static if (is(attrib : FunEvent!Leave))
563                 {
564                     CLeaveFunctions[component] ~= &__traits(getMember, component, member);
565                 } else
566                 static if (is(attrib : FunEvent!Input))
567                 {
568                     CEventHandleFunctions[component] ~= cast(FEEventHandle) &__traits(getMember, component, member);
569                 } else
570                 static if (is(attrib : FunEvent!Draw))
571                 {
572                     CDrawFunctions[component] ~= cast(FEDraw) &__traits(getMember, component, member);
573                 } else
574                 static if (is(attrib : FunEvent!GameError))
575                 {
576                     COnErrorFunctions[component] ~= &__traits(getMember, component, member);
577                 } else
578                 static if (attrib.stringof[0 .. 8] == "InThread")
579                 {
580                     CStepThreadFunctions[instance][attrib.id] ~= &__traits(getMember, instance, member);
581                 }else
582                 static if (attrig.stringof[0 .. 7] == "Trigger")
583                 {
584                     COnTriggerFunctions[component] ~= SRTrigger(attrib,
585                     cast(FETrigger) &__traits(getMember, component, member));
586                 }
587             }
588         }
589     }
590 
591     package(tida) @property FEStep[][size_t][Instance] threadSteps()
592     {
593         return IStepThreadFunctions;
594     }
595 
596     package(tida) @property SRCollider[][Instance] colliders()
597     {
598         return IColliderStructs;
599     }
600 
601     package(tida) @property FECollision[][Instance] collisionFunctions()
602     {
603         return ICollisionFunctions;
604     }
605 
606     package(tida) @property FELeave[][Component] leaveComponents()
607     {
608         return CLeaveFunctions;
609     }
610 
611     package(tida) void removeHandle(Scene scene, Instance instance) @trusted
612     {
613         IInitFunctions.remove(instance);
614         IStepFunctions.remove(instance);
615         IEntryFunctions.remove(instance);
616         IRestartFunctions.remove(instance);
617         ILeaveFunctions.remove(instance);
618         IGameStartFunctions.remove(instance);
619         IGameExitFunctions.remove(instance);
620         IGameRestartFunctions.remove(instance);
621         IEventHandleFunctions.remove(instance);
622         IDrawFunctions.remove(instance);
623         IOnErrorFunctions.remove(instance);
624         IColliderStructs.remove(instance);
625         ICollisionFunctions.remove(instance);
626         IOnTriggerFunctions.remove(instance);
627         IOnDestroyFunctions.remove(instance);
628         IStepThreadFunctions.remove(instance);
629         IOnAnyTriggerFunctions.remove(instance);
630     }
631 
632     template hasMatch(alias attrib, alias AttribType)
633     {
634         enum hasMatch = is(typeof(attrib) == AttribType) || is(attrib == AttribType) ||
635                         is(typeof(attrib) : AttribType) || is(attrib : AttribType);
636     }
637 
638     template hasAttrib(T, AttribType, string member)
639     {
640         alias same = __traits(getMember, T, member);
641 
642         static if (isFunction!(same))
643         {
644             alias attributes = __traits(getAttributes, same);
645 
646             static if (attributes.length != 0)
647             {
648                 static foreach (attrib; attributes)
649                 {
650                     static if (hasMatch!(attrib, AttribType))
651                     {
652                         static assert(isSafe!(same),
653                         "The function `" ~ member ~"` does not guarantee safe execution.");
654 
655                         enum hasAttrib = true;
656                     }else
657                     {
658                         enum hasAttrib = false;
659                     }
660                 }        
661             } else
662             {
663                 enum hasAttrib = false;
664             }
665         } else
666         {
667             enum hasAttrib = false;
668         }
669     }
670 
671     template attributeIn(T, AttribType, string member)
672     {
673         alias same = __traits(getMember, T, member);
674         alias attributes = __traits(getAttributes, same);
675 
676         static foreach (attrib; attributes)
677         {
678             static if (hasMatch!(attrib, AttribType))
679             {
680                 enum attributeIn = attrib;
681             }
682         }   
683     }
684 
685     package(tida) void instanceExplore(T)(Scene scene, T instance) @trusted
686     {
687         import std.algorithm : canFind, remove;
688         static assert(isInstance!T, "`" ~ T.stringof ~ "` is not a instance!");
689         if (instance in IInitFunctions) return;
690 
691         IInitFunctions[instance] = [];
692         IStepFunctions[instance] = [];
693         IEntryFunctions[instance] = [];
694         IRestartFunctions[instance] = [];
695         ILeaveFunctions[instance] = [];
696         IGameStartFunctions[instance] = [];
697         IGameExitFunctions[instance] = [];
698         IGameRestartFunctions[instance] = [];
699         IEventHandleFunctions[instance] = [];
700         IDrawFunctions[instance] = [];
701         IOnErrorFunctions[instance] = [];
702         IColliderStructs[instance] = [];
703         IOnTriggerFunctions[instance] = [];
704         IOnDestroyFunctions[instance] = [];
705         ICollisionFunctions[instance] = [];
706         IOnAnyTriggerFunctions[instance] = [];
707 
708         static if (T.stringof != Instance.stringof)
709         static foreach (member; __traits(allMembers, T))
710         {
711             static if (hasAttrib!(T, FunEvent!Init, member))
712             {
713                 IInitFunctions[instance] ~= &__traits(getMember, instance, member);
714             } else
715             static if (hasAttrib!(T, FunEvent!Step, member))
716             {
717                 IStepFunctions[instance] ~= &__traits(getMember, instance, member);
718             } else
719             static if (hasAttrib!(T, FunEvent!Entry, member))
720             {
721                 IEntryFunctions[instance] ~= &__traits(getMember, instance, member);
722             } else
723             static if (hasAttrib!(T, FunEvent!Restart, member))
724             {
725                 IRestartFunctions[instance] ~= &__traits(getMember, instance, member);
726             } else
727             static if (hasAttrib!(T, FunEvent!Leave, member))
728             {
729                 ILeaveFunctions[instance] ~= &__traits(getMember, instance, member);
730             } else
731             static if (hasAttrib!(T, FunEvent!GameStart, member))
732             {
733                 IGameStartFunctions[instance] ~= &__traits(getMember, instance, member);
734             } else
735             static if (hasAttrib!(T, FunEvent!GameExit, member))
736             {
737                 IGameExitFunctions[instance] ~= &__traits(getMember, instance, member);
738             } else
739             static if (hasAttrib!(T, FunEvent!GameRestart, member))
740             {
741                 IGameRestartFunctions[instance] ~= &__traits(getMember, instance, member);
742             } else
743             static if (hasAttrib!(T, FunEvent!Input, member))
744             {
745                 IEventHandleFunctions[instance] ~= &__traits(getMember, instance, member);
746             } else
747             static if (hasAttrib!(T, FunEvent!Draw, member))
748             {
749                 IDrawFunctions[instance] ~= &__traits(getMember, instance, member);
750             } else
751             static if (hasAttrib!(T, FunEvent!GameError, member))
752             {
753                 IOnErrorFunctions[instance] ~= &__traits(getMember, instance, member);
754             } else
755             static if (hasAttrib!(T, Collision, member))
756             {
757                 IColliderStructs[instance] ~= SRCollider(attributeIn!(T, Collision, member),
758                                                          &__traits(getMember, instance, member));
759             } else
760             static if (hasAttrib!(T, Trigger, member))
761             {
762                 IOnTriggerFunctions[instance] ~= SRTrigger( attributeIn!(T, Trigger, member),
763                                                             &__traits(getMember, instance, member));
764             } else
765             static if (hasAttrib!(T, FunEvent!Destroy, member))
766             {
767                 IOnDestroyFunctions[instance] ~= &__traits(getMember, instance, member);
768             } else
769             static if (hasAttrib!(T, FunEvent!AnyCollision, member))
770             {
771                 ICollisionFunctions[instance] ~= &__traits(getMember, instance, member);
772             } else
773             static if (hasAttrib!(T, FunEvent!AnyTrigger, member))
774             {
775                 IOnAnyTriggerFunctions[instance] ~= &__traits(getMember, instance, member);
776             }
777         }
778     }
779 
780     /++
781     Creates and adds a scene to the list.
782 
783     Params:
784         T = Scene name.
785 
786     Example:
787     ---
788     sceneManager.add!MyScene;
789     ---
790     +/
791     void add(T)() @trusted
792     {
793         auto scene = new T();
794         add!T(scene);
795     }
796 
797     void remove(T)(T scene) @trusted
798     {
799         scenes.remove(scene.name);
800         destroy(scene);
801     }
802 
803     void remove(T)() @trusted
804     {
805         static assert(isScene!T, "`" ~ T.stringof ~ "` is not a scene!");
806 
807         foreach(scene; scenes)
808         {
809             if((cast(T) scene) !is null) {
810                 remove(scene);
811                 return;
812             }
813         }
814     }
815 
816     void remove(string name) @trusted
817     {
818         foreach(scene; scenes) {
819             if(scene.name == name) {
820                 remove(scene);
821                 return;
822             }
823         }
824     }
825 
826     private void exploreScene(T)(T scene) @trusted
827     {
828         InitFunctions[scene] = [];
829         StepFunctions[scene] = [];
830         EntryFunctions[scene] = [];
831         RestartFunctions[scene] = [];
832         LeaveFunctions[scene] = [];
833         GameStartFunctions[scene] = [];
834         GameExitFunctions[scene] = [];
835         GameRestartFunctions[scene] = [];
836         EventHandleFunctions[scene] = [];
837         DrawFunctions[scene] = [];
838         OnErrorFunctions[scene] = [];
839         OnTriggerFunctions[scene] = [];
840         OnDestroyFunctions[scene] = [];
841 
842         static if (T.stringof != Instance.stringof)
843         static foreach (member; __traits(allMembers, T))
844         {
845             static if (hasAttrib!(T, FunEvent!Init, member))
846             {
847                 InitFunctions[scene] ~= &__traits(getMember, scene, member);
848             } else
849             static if (hasAttrib!(T, FunEvent!Step, member))
850             {
851                 StepFunctions[scene] ~= &__traits(getMember, scene, member);
852             } else
853             static if (hasAttrib!(T, FunEvent!Entry, member))
854             {
855                 EntryFunctions[scene] ~= &__traits(getMember, scene, member);
856             } else
857             static if (hasAttrib!(T, FunEvent!Restart, member))
858             {
859                 RestartFunctions[scene] ~= &__traits(getMember, scene, member);
860             } else
861             static if (hasAttrib!(T, FunEvent!Leave, member))
862             {
863                 LeaveFunctions[scene] ~= &__traits(getMember, scene, member);
864             } else
865             static if (hasAttrib!(T, FunEvent!GameStart, member))
866             {
867                 GameStartFunctions[scene] ~= &__traits(getMember, scene, member);
868             } else
869             static if (hasAttrib!(T, FunEvent!GameExit, member))
870             {
871                 GameExitFunctions[scene] ~= &__traits(getMember, scene, member);
872             } else
873             static if (hasAttrib!(T, FunEvent!GameRestart, member))
874             {
875                 GameRestartFunctions[scene] ~= &__traits(getMember, scene, member);
876             } else
877             static if (hasAttrib!(T, FunEvent!Input, member))
878             {
879                 EventHandleFunctions[scene] ~= &__traits(getMember, scene, member);
880             } else
881             static if (hasAttrib!(T, FunEvent!Draw, member))
882             {
883                 DrawFunctions[scene] ~= &__traits(getMember, scene, member);
884             } else
885             static if (hasAttrib!(T, FunEvent!GameError, member))
886             {
887                 OnErrorFunctions[scene] ~= &__traits(getMember, scene, member);
888             } else
889             static if (hasAttrib!(T, Trigger, member))
890             {
891                 IOnTriggerFunctions[scene] ~= SRTrigger( attributeIn!(T, Collision, member),
892                                                             &__traits(getMember, scene, member));
893             } else
894             static if (hasAttrib!(T, FunEvent!AnyCollision, member))
895             {
896                 ICollisionFunctions[scene] ~= &__traits(getMember, scene, member);
897             } else
898             static if (hasAttrib!(T, FunEvent!AnyTrigger, member))
899             {
900                 IOnAnyTriggerFunctions[scene] ~= &__traits(getMember, scene, member);
901             }
902         }
903         //static foreach(member; __traits(allMembers, T))
904         //{
905         //    static foreach(attrib; __traits(getAttributes, __traits(getMember, scene, member)))
906         //    {
907         //        static if (is(attrib : FunEvent!Init))
908         //        {
909         //            InitFunctions[scene] ~= &__traits(getMember, scene, member);
910         //        }else
911         //        static if (is(attrib : FunEvent!Step))
912         //        {
913         //            StepFunctions[scene] ~= &__traits(getMember, scene, member);
914         //        }else
915         //        static if (is(attrib : FunEvent!Entry))
916         //        {
917         //            EntryFunctions[scene] ~= &__traits(getMember, scene, member);
918         //        }else
919         //        static if (is(attrib : FunEvent!Restart))
920         //        {
921         //            RestartFunctions[scene] ~= &__traits(getMember, scene, member);
922         //        }else
923         //        static if (is(attrib : FunEvent!Leave))
924         //        {
925         //            LeaveFunctions[scene] ~= &__traits(getMember, scene, member);
926         //        }else
927         //        static if (is(attrib : FunEvent!GameStart))
928         //        {
929         //            GameStartFunctions[scene] ~= &__traits(getMember, scene, member);
930         //        }else
931         //        static if (is(attrib : FunEvent!GameExit))
932         //        {
933         //            GameExitFunctions[scene] ~= &__traits(getMember, scene, member);
934         //        }else
935         //        static if (is(attrib : FunEvent!GameRestart))
936         //        {
937         //            GameRestartFunctions[scene] ~= &__traits(getMember, scene, member);
938         //        }else
939         //        static if (is(attrib : FunEvent!Input))
940         //        {
941         //            EventHandleFunctions[scene] ~= cast(FEEventHandle) &__traits(getMember, scene, member);
942         //        }else
943         //        static if (is(attrib : FunEvent!Draw))
944         //        {
945         //            DrawFunctions[scene] ~= cast(FEDraw) &__traits(getMember, scene, member);
946         //        }else
947         //        static if (is(attrib : FunEvent!GameError))
948         //        {
949         //            OnErrorFunctions[scene] ~= &__traits(getMember, scene, member);
950         //        }else
951         //        static if (is(attrib : FunEvent!Destroy))
952         //        {
953         //            OnDestroyFunctions[scene] ~= &__traits(getMember, scene, member);
954         //        }else
955         //        static if (attrib.stringof[0 .. 8] == "InThread")
956         //        {
957         //            StepThreadFunctions[scene][attrib.id] ~= &__traits(getMember, scene, member);
958         //        }else
959         //        static if (attrib.stringof[0 .. 7] == "Trigger")
960         //        {
961         //            OnTriggerFunctions[scene] ~= SRTrigger(attrib,
962         //            cast(FETrigger) &__traits(getMember, scene, member));
963         //        }
964         //    }
965         //}
966     }
967 
968     public
969     {
970         /++
971         Array of requests. At each stroke of the cycle, it is checked,
972         processed and cleaned. If an error occurs during the request,
973         they are added to `apiError`.
974         +/
975         APIResponse[] api;
976 
977         /++
978         An array of request errors associated with the request type.
979         +/
980         uint[uint] apiError;
981     }
982 
983     /++
984     Exits the game with a successful error code.
985     +/
986     void close(int code = 0) @safe
987     {
988         api ~= APIResponse(APIType.GameClose, code);
989     }
990 
991     /++
992     Creates the specified count of anonymous threads.
993 
994     Params:
995         count = Count anonymous threads.
996     +/
997     void initThread(uint count = 1) @safe
998     {
999         api ~= APIResponse(APIType.ThreadCreate, count);
1000     }
1001 
1002     /++
1003     Pauses said thread.
1004 
1005     Params:
1006         value = Thread identificator.
1007     +/
1008     void pauseThread(uint value) @safe
1009     {
1010         api ~= APIResponse(APIType.ThreadPause, value);
1011     }
1012 
1013     /++
1014     Resumes said thread.
1015 
1016     Params:
1017         value = Thread identificator.
1018     +/
1019     void resumeThread(uint value) @safe
1020     {
1021         api ~= APIResponse(APIType.ThreadResume, value);
1022     }
1023 
1024     void stopThread(uint value) @safe
1025     {
1026         api ~= APIResponse(APIType.ThreadClose, value);
1027     }
1028 
1029     /++
1030     Goes to the first scene added.
1031     +/
1032     void inbegin() @safe
1033     {
1034         gotoin(_ofbegin);
1035     }
1036 
1037     /++
1038     Goes to the scene by its string name.
1039 
1040     Params:
1041         name = Scene name.
1042     +/
1043     void gotoin(string name)
1044     {
1045         foreach (inscene; scenes)
1046         {
1047             if(inscene.name == name)
1048             {
1049                 gotoin(inscene);
1050                 break;
1051             }
1052         }
1053     }
1054 
1055     /++
1056     Goes to the scene by its class.
1057 
1058     Params:
1059         Name = Scene.
1060     +/
1061     void gotoin(Name)()
1062     {
1063         foreach (s; scenes)
1064         {
1065             if ((cast(Name) s) !is null)
1066             {
1067                 gotoin(s);
1068                 return;
1069             }
1070         }
1071 
1072         throw new Exception("Not find this scene!");
1073     }
1074 
1075     /++
1076     Moves to the scene at the pointer.
1077 
1078     It is such a function that generates initialization events, entry,
1079     transferring the context to the scene and causing the corresponding
1080     events to lose the context.
1081 
1082     Params:
1083         scene = Scene heir.
1084     +/
1085     void gotoin(Scene scene) @trusted
1086     in(hasScene(scene))
1087     do
1088     {
1089         _previous = current;
1090 
1091         if (current !is null)
1092         {
1093             if (current in LeaveFunctions)
1094             {
1095                 foreach (fun; LeaveFunctions[current])
1096                 {
1097                     fun();
1098                 }
1099             }
1100 
1101             foreach (instance; current.list())
1102             {
1103                 if (instance in ILeaveFunctions)
1104                 {
1105                     foreach (fun; ILeaveFunctions[instance])
1106                     {
1107                         fun();
1108                     }
1109                 }
1110             }
1111         }
1112 
1113         if (current !is null)
1114         {
1115             Instance[] persistents;
1116 
1117             foreach (instance; _previous.list())
1118             {
1119                 if (instance.persistent)
1120                     persistents ~= instance;
1121             }
1122 
1123             foreach (e; persistents)
1124             {
1125                 auto threadID = e.threadid;
1126                 current.instanceDestroy!InScene(e, false);
1127 
1128                 if (scene.isThreadExists(threadID))
1129                     scene.add(e,threadID);
1130                 else
1131                     scene.add(e);
1132             }
1133         }
1134 
1135         _initable = scene;
1136 
1137         if (!scene.isInit)
1138         {
1139             if (scene in InitFunctions)
1140             {
1141                 foreach (fun; InitFunctions[scene])
1142                 {
1143                     fun();
1144                 }
1145             }
1146 
1147             foreach (instance; scene.list())
1148             {
1149                 if (instance in IInitFunctions)
1150                 {
1151                     foreach (fun; IInitFunctions[instance])
1152                     {
1153                         fun();
1154                     }
1155                 }
1156             }
1157 
1158             scene.isInit = true;
1159         }else
1160         {
1161             if (scene in RestartFunctions)
1162             {
1163                 foreach (fun; RestartFunctions[scene])
1164                 {
1165                     fun();
1166                 }
1167             }
1168 
1169             foreach (instance; scene.list())
1170             {
1171                 if (instance in IRestartFunctions)
1172                 {
1173                     foreach (fun; IRestartFunctions[instance])
1174                     {
1175                         fun();
1176                     }
1177                 }
1178             }
1179         }
1180 
1181         if (scene in EntryFunctions)
1182         {
1183             foreach(fun; EntryFunctions[scene])
1184             {
1185                 fun();
1186             }
1187         }
1188 
1189         foreach (instance; scene.list())
1190         {
1191             if (instance in IEntryFunctions)
1192             {
1193                 foreach (fun; IEntryFunctions[instance])
1194                 {
1195                     fun();
1196                 }
1197             }
1198         }
1199 
1200         _initable = null;
1201 
1202         _current = scene;
1203     }
1204 
1205     /++
1206     Calling the game launch event.
1207 
1208     Should be called before all events, before the beginning of the
1209     cycle of life.
1210     +/
1211     void callGameStart() @trusted
1212     {
1213         foreach (scene; scenes)
1214         {
1215             if (scene in GameStartFunctions)
1216             {
1217                 foreach (fun; GameStartFunctions[scene])
1218                 {
1219                     fun();
1220                 }
1221             }
1222 
1223             foreach (instance; scene.list())
1224             {
1225                 if (instance.active && !instance.onlyDraw)
1226                 {
1227                     if (instance in IGameStartFunctions)
1228                     {
1229                         foreach (fun; IGameStartFunctions[instance])
1230                         {
1231                             fun();
1232                         }
1233                     }
1234                 }
1235             }
1236         }
1237     }
1238 
1239     /++
1240     Game completion call events (successful).
1241     The unsuccessful event should raise the `onError` event.
1242     +/
1243     void callGameExit() @trusted
1244     {
1245         foreach (scene; scenes)
1246         {
1247             if (scene in GameExitFunctions)
1248             {
1249                 foreach (fun; GameExitFunctions[scene])
1250                 {
1251                     fun();
1252                 }
1253             }
1254 
1255             foreach (instance; scene.list())
1256             {
1257                 if (instance.active && !instance.onlyDraw)
1258                 {
1259                     if (instance in IGameExitFunctions)
1260                     {
1261                         foreach (fun; IGameExitFunctions[instance])
1262                         {
1263                             fun();
1264                         }
1265                     }
1266                 }
1267             }
1268         }
1269     }
1270 
1271     /++
1272     Triggering an emergency event.
1273 
1274     Does not terminate the game, should be called on exceptions. After that,
1275     the programmer himself decides what to do next (if he implements his own
1276     life cycle). Called usually on `scope (failure)`, however, it will not
1277     throw a specific exception.
1278     +/
1279     void callOnError() @trusted
1280     {
1281         if (current !is null)
1282         {
1283             if (current in OnErrorFunctions)
1284             {
1285                 foreach (fun; OnErrorFunctions[current])
1286                 {
1287                     fun();
1288                 }
1289             }
1290 
1291             foreach (instance; current.list())
1292             {
1293                 if (instance.active && !instance.onlyDraw)
1294                 {
1295                     if (instance in IOnErrorFunctions)
1296                     {
1297                         foreach (fun; IOnErrorFunctions[instance])
1298                         {
1299                             fun();
1300                         }
1301                     }
1302                 }
1303             }
1304         }
1305     }
1306 
1307     /++
1308     Calling a game step. Should always be called during a loop step in an
1309     exception when the thread is suspended.
1310 
1311     Params:
1312         thread = Thread identificator.
1313         rend   = Renderer instance.
1314     +/
1315     void callStep(size_t thread, IRenderer rend) @trusted
1316     {
1317         if (current !is null)
1318         {
1319             current.worldCollision();
1320 
1321             if (thread == 0)
1322             if (current in StepFunctions)
1323             {
1324                 foreach (fun; StepFunctions[current])
1325                 {
1326                     fun();
1327                 }
1328             }
1329 
1330             if (current in StepThreadFunctions)
1331             if (thread in StepThreadFunctions[current])
1332             {
1333                 foreach (fun; StepThreadFunctions[current][thread])
1334                     fun();
1335             }
1336 
1337             foreach (instance; current.getThreadList(thread))
1338             {
1339                 if (instance.isDestroy)
1340                 {
1341                     current.instanceDestroy!InMemory(instance);
1342                     current.sort();
1343                     continue;
1344                 }
1345 
1346                 if (!instance.active || instance.onlyDraw) continue;
1347 
1348                 if (instance in IStepFunctions)
1349                 {
1350                     foreach (fun; IStepFunctions[instance])
1351                     {
1352                         fun();
1353                     }
1354                 }
1355 
1356                 foreach (component; instance.getComponents())
1357                 {
1358                     if (component in CStepFunctions)
1359                     {
1360                         foreach (fun; CStepFunctions[component])
1361                         {
1362                             fun();
1363                         }
1364                     }
1365                 }
1366             }
1367 
1368             foreach(instance; current.list())
1369             {
1370                 if (!instance.active || instance.onlyDraw) continue;
1371 
1372                 if (instance in IStepThreadFunctions)
1373                 if (thread in IStepThreadFunctions[instance])
1374                 {
1375                     foreach (fun; IStepThreadFunctions[instance][thread])
1376                         fun();
1377                 }
1378 
1379                 foreach (component; instance.getComponents())
1380                 {
1381                     if (component in CStepThreadFunctions)
1382                     if (thread in CStepThreadFunctions[component])
1383                     {
1384                         foreach(fun; CStepThreadFunctions[component][thread])
1385                         {
1386                             fun();
1387                         }
1388                     }
1389                 }
1390             }
1391         }
1392     }
1393 
1394     /++
1395     System event event for scenes and instances of the current context.
1396 
1397     Params:
1398         event = System event handler instance.
1399     +/
1400     void callEvent(EventHandler event) @trusted
1401     {
1402         if (current !is null)
1403         {
1404             if (current in EventHandleFunctions)
1405             {
1406                 foreach (fun; EventHandleFunctions[current])
1407                 {
1408                     fun(event);
1409                 }
1410             }
1411 
1412             foreach (instance; current.list())
1413             {
1414                 if (instance.active && !instance.onlyDraw)
1415                 {
1416                     if (instance in IEventHandleFunctions)
1417                     {
1418                         foreach(fun; IEventHandleFunctions[instance])
1419                         {
1420                             fun(event);
1421                         }
1422                     }
1423 
1424                     foreach (component; instance.getComponents())
1425                     {
1426                         if (component in CEventHandleFunctions)
1427                         {
1428                             foreach(fun; CEventHandleFunctions[component])
1429                             {
1430                                 fun(event);
1431                             }
1432                         }
1433                     }
1434                 }
1435             }
1436         }
1437     }
1438 
1439     /++
1440     Calling an event to render scenes and instances of the current context.
1441 
1442     Params:
1443         render = Render instance.
1444     +/
1445     void callDraw(IRenderer render) @trusted
1446     {
1447         import tida.vector;
1448 
1449         if (current !is null)
1450         {
1451             if (current in DrawFunctions)
1452             {
1453                 foreach (fun; DrawFunctions[current])
1454                 {
1455                     fun(render);
1456                 }
1457             }
1458 
1459             foreach (instance; current.getAssortedInstances())
1460             {
1461                 if (instance.active && instance.visible)
1462                 {
1463                     render.draw(instance.spriteDraw(), instance.position);
1464 
1465                     if (instance in IDrawFunctions)
1466                     {
1467                         foreach (fun; IDrawFunctions[instance])
1468                         {
1469                             fun(render);
1470                         }
1471                     }
1472 
1473                     foreach (component; instance.getComponents())
1474                     {
1475                         if (component in CDrawFunctions)
1476                         {
1477                             foreach (fun; CDrawFunctions[component])
1478                             {
1479                                 fun(render);
1480                             }
1481                         }
1482                     }
1483                 }
1484             }
1485         }
1486     }
1487 
1488     /// Free memory.
1489     void free() @safe
1490     {
1491         _scenes = null;
1492     }
1493 
1494     ~this() @safe
1495     {
1496         free();
1497     }
1498 }
1499 
1500 unittest
1501 {
1502     initSceneManager();
1503 
1504     class A : Scene
1505     {
1506         this() @safe
1507         {
1508             name = "Test";
1509         }
1510     }
1511 
1512     sceneManager.add(new A());
1513     assert(("Test" in sceneManager.scenes) !is null);
1514 }
1515 
1516 unittest
1517 {
1518     initSceneManager();
1519 
1520     class A : Scene
1521     {
1522         @Event!Init
1523         void onInit() @safe { }
1524     }
1525 
1526     A obj = new A();
1527     sceneManager.add(obj);
1528 
1529     assert((sceneManager.InitFunctions[obj][0].ptr) == ((&obj.onInit).ptr));
1530 }
1531 
1532 unittest
1533 {
1534     initSceneManager();
1535 
1536     class A : Scene
1537     {
1538         this() @safe
1539         {
1540             name = "Test";
1541         }
1542     }
1543 
1544     sceneManager.add(new A());
1545     assert(sceneManager.hasScene("Test"));
1546 }