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         foreach (scene; scenes)
387         {
388             if ((cast(Name) scene) !is null)
389                 return true;
390         }
391 
392         return false;
393     }
394 
395     /++
396     Checks if there is a scene with the specified name.
397 
398     Params:
399         name = Scene name.
400     +/
401     bool hasScene(string name)
402     {
403         foreach (scene; scenes)
404         {
405             if (scene.name == name) return true;
406         }
407 
408         return false;
409     }
410 
411     /++
412     Adds a scene to the list.
413 
414     Params:
415         scene = Scene.
416     +/
417     void add(T)(T scene)
418     {
419         exploreScene!T(scene);
420 
421         if (_ofbegin is null)
422             _ofbegin = scene;
423 
424         _scenes[scene.name] = scene;
425     }
426 
427     protected
428     {
429         import std.container, std.range, std.traits;
430         import tida.component : Component;
431 
432         alias FEInit = void delegate() @safe;
433         alias FEStep = void delegate() @safe;
434         alias FERestart = void delegate() @safe;
435         alias FEEntry = void delegate() @safe;
436         alias FELeave = void delegate() @safe;
437         alias FEGameStart = void delegate() @safe;
438         alias FEGameExit = void delegate() @safe;
439         alias FEGameRestart = void delegate() @safe;
440         alias FEEventHandle = void delegate(EventHandler) @safe;
441         alias FEDraw = void delegate(IRenderer) @safe;
442         alias FEOnError = void delegate() @safe;
443         alias FECollision = void delegate(Instance) @safe;
444         alias FETrigger = void delegate() @safe;
445         alias FEDestroy = void delegate(Instance) @safe;
446 
447         alias FECInit = void delegate(Instance) @safe;
448 
449         struct SRCollider
450         {
451             Collision ev;
452             FECollision fun;
453         }
454 
455         struct SRTrigger
456         {
457             Trigger ev;
458             FETrigger fun;
459         }
460 
461         FEInit[][Scene] InitFunctions;
462         FEStep[][Scene] StepFunctions;
463         FEStep[][size_t][Scene] StepThreadFunctions;
464         FERestart[][Scene] RestartFunctions;
465         FEEntry[][Scene] EntryFunctions;
466         FELeave[][Scene] LeaveFunctions;
467         FEGameStart[][Scene] GameStartFunctions;
468         FEGameExit[][Scene] GameExitFunctions;
469         FEGameRestart[][Scene] GameRestartFunctions;
470         FEEventHandle[][Scene] EventHandleFunctions;
471         FEDraw[][Scene] DrawFunctions;
472         FEOnError[][Scene] OnErrorFunctions;
473         SRTrigger[][Scene] OnTriggerFunctions;
474         FEDestroy[][Scene] OnDestroyFunctions;
475 
476         FEInit[][Instance] IInitFunctions;
477         FEStep[][Instance] IStepFunctions;
478         FEStep[][size_t][Instance] IStepThreadFunctions;
479         FERestart[][Instance] IRestartFunctions;
480         FEEntry[][Instance] IEntryFunctions;
481         FELeave[][Instance] ILeaveFunctions;
482         FEGameStart[][Instance] IGameStartFunctions;
483         FEGameExit[][Instance] IGameExitFunctions;
484         FEGameRestart[][Instance] IGameRestartFunctions;
485         FEEventHandle[][Instance] IEventHandleFunctions;
486         FEDraw[][Instance] IDrawFunctions;
487         FEOnError[][Instance] IOnErrorFunctions;
488         SRCollider[][Instance] IColliderStructs;
489         FECollision[][Instance] ICollisionFunctions;
490         SRTrigger[][Instance] IOnTriggerFunctions;
491         FEDestroy[][Instance] IOnDestroyFunctions;
492 
493         FEStep[][Component] CStepFunctions;
494         FEStep[][size_t][Component] CStepThreadFunctions;
495         FELeave[][Component] CLeaveFunctions;
496         FEEventHandle[][Component] CEventHandleFunctions;
497         FEDraw[][Component] CDrawFunctions;
498         FEOnError[][Component] COnErrorFunctions;
499         SRTrigger[][Component] COnTriggerFunctions;
500     }
501 
502     /++
503     Raise the event of destruction of the instance. (@FunEvent!Destroy)
504 
505     Params:
506         instance = Instance.
507     +/
508     void destroyEventCall(T)(T instance) @trusted
509     {
510         static assert(isInstance!T, "`" ~ T.stringof ~ "` is not a instance!");
511         foreach(func; IOnDestroyFunctions[instance]) func(instance);
512     }
513 
514     /++
515     Reise the event of destruction in current scene. (@FunEvent!Destroy)
516 
517     Params:
518         scene = Current scene.
519         instance = Instance.
520     +/
521     void destroyEventSceneCall(T, R)(T scene, R instance) @trusted
522     {
523         foreach(func; OnDestroyFunctions[scene]) func(instance);
524     }
525 
526     package(tida) void componentExplore(T)(Instance instance, T component) @trusted
527     {
528         CStepFunctions[component] = [];
529         CLeaveFunctions[component] = [];
530         CEventHandleFunctions[component] = [];
531         CDrawFunctions[component] = [];
532         COnErrorFunctions[component] = [];
533         COnTriggerFunctions[component] = [];
534 
535         static foreach (member; __traits(allMembers, T))
536         {
537             static foreach (attrib; __traits(getAttributes, __traits(getMember, component, member)))
538             {
539                 static if (is(attrib : FunEvent!Init))
540                 {
541                     auto fun = cast(FECInit) &__traits(getMember, component, member);
542                     fun(instance);
543                 } else
544                 static if (is(attrib : FunEvent!Step))
545                 {
546                     CStepFunctions[component] ~= &__traits(getMember, component, member);
547                 } else
548                 static if (is(attrib : FunEvent!Leave))
549                 {
550                     CLeaveFunctions[component] ~= &__traits(getMember, component, member);
551                 } else
552                 static if (is(attrib : FunEvent!Input))
553                 {
554                     CEventHandleFunctions[component] ~= cast(FEEventHandle) &__traits(getMember, component, member);
555                 } else
556                 static if (is(attrib : FunEvent!Draw))
557                 {
558                     CDrawFunctions[component] ~= cast(FEDraw) &__traits(getMember, component, member);
559                 } else
560                 static if (is(attrib : FunEvent!GameError))
561                 {
562                     COnErrorFunctions[component] ~= &__traits(getMember, component, member);
563                 } else
564                 static if (attrib.stringof[0 .. 8] == "InThread")
565                 {
566                     CStepThreadFunctions[instance][attrib.id] ~= &__traits(getMember, instance, member);
567                 }else
568                 static if (attrig.stringof[0 .. 7] == "Trigger")
569                 {
570                     COnTriggerFunctions[component] ~= SRTrigger(attrib,
571                     cast(FETrigger) &__traits(getMember, component, member));
572                 }
573             }
574         }
575     }
576 
577     package(tida) @property FEStep[][size_t][Instance] threadSteps()
578     {
579         return IStepThreadFunctions;
580     }
581 
582     package(tida) @property SRCollider[][Instance] colliders()
583     {
584         return IColliderStructs;
585     }
586 
587     package(tida) @property FECollision[][Instance] collisionFunctions()
588     {
589         return ICollisionFunctions;
590     }
591 
592     package(tida) @property FELeave[][Component] leaveComponents()
593     {
594         return CLeaveFunctions;
595     }
596 
597     package(tida) void removeHandle(Scene scene, Instance instance) @trusted
598     {
599         IInitFunctions.remove(instance);
600         IStepFunctions.remove(instance);
601         IEntryFunctions.remove(instance);
602         IRestartFunctions.remove(instance);
603         ILeaveFunctions.remove(instance);
604         IGameStartFunctions.remove(instance);
605         IGameExitFunctions.remove(instance);
606         IGameRestartFunctions.remove(instance);
607         IEventHandleFunctions.remove(instance);
608         IDrawFunctions.remove(instance);
609         IOnErrorFunctions.remove(instance);
610         IColliderStructs.remove(instance);
611         ICollisionFunctions.remove(instance);
612         IOnTriggerFunctions.remove(instance);
613         IOnDestroyFunctions.remove(instance);
614         IStepThreadFunctions.remove(instance);
615     }
616 
617     package(tida) void instanceExplore(T)(Scene scene, T instance) @trusted
618     {
619         import std.algorithm : canFind, remove;
620         static assert(isInstance!T, "`" ~ T.stringof ~ "` is not a instance!");
621         if (instance in IInitFunctions) return;
622 
623         IInitFunctions[instance] = [];
624         IStepFunctions[instance] = [];
625         IEntryFunctions[instance] = [];
626         IRestartFunctions[instance] = [];
627         ILeaveFunctions[instance] = [];
628         IGameStartFunctions[instance] = [];
629         IGameExitFunctions[instance] = [];
630         IGameRestartFunctions[instance] = [];
631         IEventHandleFunctions[instance] = [];
632         IDrawFunctions[instance] = [];
633         IOnErrorFunctions[instance] = [];
634         IColliderStructs[instance] = [];
635         IOnTriggerFunctions[instance] = [];
636         IOnDestroyFunctions[instance] = [];
637         ICollisionFunctions[instance] = [];
638 
639         static foreach (member; __traits(allMembers, T))
640         {
641             static foreach (attrib; __traits(getAttributes, __traits(getMember, instance, member)))
642             {
643                 static if (is(attrib : FunEvent!Init))
644                 {
645                     IInitFunctions[instance] ~= &__traits(getMember, instance, member);
646                 }else
647                 static if (is(attrib : FunEvent!Step))
648                 {
649                     IStepFunctions[instance] ~= &__traits(getMember, instance, member);
650                 }else
651                 static if (is(attrib : FunEvent!Entry))
652                 {
653                     IEntryFunctions[instance] ~= &__traits(getMember, instance, member);
654                 }else
655                 static if (is(attrib : FunEvent!Restart))
656                 {
657                     IRestartFunctions[instance] ~= &__traits(getMember, instance, member);
658                 }else
659                 static if (is(attrib : FunEvent!Leave))
660                 {
661                     ILeaveFunctions[instance] ~= &__traits(getMember, instance, member);
662                 }else
663                 static if (is(attrib : FunEvent!GameStart))
664                 {
665                     IGameStartFunctions[instance] ~= &__traits(getMember, instance, member);
666                 }else
667                 static if (is(attrib : FunEvent!GameExit))
668                 {
669                     IGameExitFunctions[instance] ~= &__traits(getMember, instance, member);
670                 }else
671                 static if (is(attrib : FunEvent!GameRestart))
672                 {
673                     IGameRestartFunctions[instance] ~= &__traits(getMember, instance, member);
674                 }else
675                 static if (is(attrib : FunEvent!Input))
676                 {
677                     IEventHandleFunctions[instance] ~= cast(FEEventHandle) &__traits(getMember, instance, member);
678                 }else
679                 static if (is(attrib : FunEvent!Draw))
680                 {
681                     IDrawFunctions[instance] ~= cast(FEDraw) &__traits(getMember, instance, member);
682                 }else
683                 static if (is(attrib : FunEvent!GameError))
684                 {
685                     IOnErrorFunctions[instance] ~= &__traits(getMember, instance, member);
686                 }else
687                 static if (is(attrib : FunEvent!Destroy))
688                 {
689                     IOnDestroyFunctions[instance] ~= &__traits(getMember, instance, member);
690                 }else
691                 static if (is(attrib : FunEvent!AnyCollision))
692                 {
693                     ICollisionFunctions[instance] ~= &__traits(getMember, instance, member);
694                 }else
695                 static if (attrib.stringof[0 .. 8] == "InThread")
696                 {
697                     IStepThreadFunctions[instance][attrib.id] ~= &__traits(getMember, instance, member);
698                 }else
699                 static if (attrib.stringof[0 .. 7] == "Trigger")
700                 {
701                     IOnTriggerFunctions[instance] ~= SRTrigger(attrib,
702                     cast(FETrigger) &__traits(getMember, instance, member));
703                 }else
704                 static if (attrib.stringof[0 .. 9] == "Collision")
705                 {
706                     IColliderStructs[instance] ~= SRCollider(attrib,
707                     cast(FECollision) &__traits(getMember, instance, member));
708                 }
709             }
710         }
711     }
712 
713     /++
714     Creates and adds a scene to the list.
715 
716     Params:
717         T = Scene name.
718 
719     Example:
720     ---
721     sceneManager.add!MyScene;
722     ---
723     +/
724     void add(T)() @trusted
725     {
726         auto scene = new T();
727         add!T(scene);
728     }
729 
730     void remove(T)(T scene) @trusted
731     {
732         scenes.remove(scene.name);
733         destroy(scene);
734     }
735 
736     void remove(T)() @trusted
737     {
738         static assert(isScene!T, "`" ~ T.stringof ~ "` is not a scene!");
739 
740         foreach(scene; scenes)
741         {
742             if((cast(T) scene) !is null) {
743                 remove(scene);
744                 return;
745             }
746         }
747     }
748 
749     void remove(string name) @trusted
750     {
751         foreach(scene; scenes) {
752             if(scene.name == name) {
753                 remove(scene);
754                 return;
755             }
756         }
757     }
758 
759     private void exploreScene(T)(T scene) @trusted
760     {
761         InitFunctions[scene] = [];
762         StepFunctions[scene] = [];
763         EntryFunctions[scene] = [];
764         RestartFunctions[scene] = [];
765         LeaveFunctions[scene] = [];
766         GameStartFunctions[scene] = [];
767         GameExitFunctions[scene] = [];
768         GameRestartFunctions[scene] = [];
769         EventHandleFunctions[scene] = [];
770         DrawFunctions[scene] = [];
771         OnErrorFunctions[scene] = [];
772         OnTriggerFunctions[scene] = [];
773         OnDestroyFunctions[scene] = [];
774 
775         static foreach(member; __traits(allMembers, T))
776         {
777             static foreach(attrib; __traits(getAttributes, __traits(getMember, scene, member)))
778             {
779                 static if (is(attrib : FunEvent!Init))
780                 {
781                     InitFunctions[scene] ~= &__traits(getMember, scene, member);
782                 }else
783                 static if (is(attrib : FunEvent!Step))
784                 {
785                     StepFunctions[scene] ~= &__traits(getMember, scene, member);
786                 }else
787                 static if (is(attrib : FunEvent!Entry))
788                 {
789                     EntryFunctions[scene] ~= &__traits(getMember, scene, member);
790                 }else
791                 static if (is(attrib : FunEvent!Restart))
792                 {
793                     RestartFunctions[scene] ~= &__traits(getMember, scene, member);
794                 }else
795                 static if (is(attrib : FunEvent!Leave))
796                 {
797                     LeaveFunctions[scene] ~= &__traits(getMember, scene, member);
798                 }else
799                 static if (is(attrib : FunEvent!GameStart))
800                 {
801                     GameStartFunctions[scene] ~= &__traits(getMember, scene, member);
802                 }else
803                 static if (is(attrib : FunEvent!GameExit))
804                 {
805                     GameExitFunctions[scene] ~= &__traits(getMember, scene, member);
806                 }else
807                 static if (is(attrib : FunEvent!GameRestart))
808                 {
809                     GameRestartFunctions[scene] ~= &__traits(getMember, scene, member);
810                 }else
811                 static if (is(attrib : FunEvent!Input))
812                 {
813                     EventHandleFunctions[scene] ~= cast(FEEventHandle) &__traits(getMember, scene, member);
814                 }else
815                 static if (is(attrib : FunEvent!Draw))
816                 {
817                     DrawFunctions[scene] ~= cast(FEDraw) &__traits(getMember, scene, member);
818                 }else
819                 static if (is(attrib : FunEvent!GameError))
820                 {
821                     OnErrorFunctions[scene] ~= &__traits(getMember, scene, member);
822                 }else
823                 static if (is(attrib : FunEvent!Destroy))
824                 {
825                     OnDestroyFunctions[scene] ~= &__traits(getMember, scene, member);
826                 }else
827                 static if (attrib.stringof[0 .. 8] == "InThread")
828                 {
829                     StepThreadFunctions[scene][attrib.id] ~= &__traits(getMember, scene, member);
830                 }else
831                 static if (attrib.stringof[0 .. 7] == "Trigger")
832                 {
833                     OnTriggerFunctions[scene] ~= SRTrigger(attrib,
834                     cast(FETrigger) &__traits(getMember, scene, member));
835                 }
836             }
837         }
838     }
839 
840     public
841     {
842         /++
843         Array of requests. At each stroke of the cycle, it is checked,
844         processed and cleaned. If an error occurs during the request,
845         they are added to `apiError`.
846         +/
847         APIResponse[] api;
848 
849         /++
850         An array of request errors associated with the request type.
851         +/
852         uint[uint] apiError;
853     }
854 
855     /++
856     Exits the game with a successful error code.
857     +/
858     void close(int code = 0) @safe
859     {
860         api ~= APIResponse(APIType.GameClose, code);
861     }
862 
863     /++
864     Creates the specified count of anonymous threads.
865 
866     Params:
867         count = Count anonymous threads.
868     +/
869     void initThread(uint count = 1) @safe
870     {
871         api ~= APIResponse(APIType.ThreadCreate, count);
872     }
873 
874     /++
875     Pauses said thread.
876 
877     Params:
878         value = Thread identificator.
879     +/
880     void pauseThread(uint value) @safe
881     {
882         api ~= APIResponse(APIType.ThreadPause, value);
883     }
884 
885     /++
886     Resumes said thread.
887 
888     Params:
889         value = Thread identificator.
890     +/
891     void resumeThread(uint value) @safe
892     {
893         api ~= APIResponse(APIType.ThreadResume, value);
894     }
895 
896     void stopThread(uint value) @safe
897     {
898         api ~= APIResponse(APIType.ThreadClose, value);
899     }
900 
901     /++
902     Goes to the first scene added.
903     +/
904     void inbegin() @safe
905     {
906         gotoin(_ofbegin);
907     }
908 
909     /++
910     Goes to the scene by its string name.
911 
912     Params:
913         name = Scene name.
914     +/
915     void gotoin(string name)
916     {
917         foreach (inscene; scenes)
918         {
919             if(inscene.name == name)
920             {
921                 gotoin(inscene);
922                 break;
923             }
924         }
925     }
926 
927     /++
928     Goes to the scene by its class.
929 
930     Params:
931         Name = Scene.
932     +/
933     void gotoin(Name)()
934     {
935         foreach (s; scenes)
936         {
937             if ((cast(Name) s) !is null)
938             {
939                 gotoin(s);
940                 return;
941             }
942         }
943 
944         throw new Exception("Not find this scene!");
945     }
946 
947     /++
948     Moves to the scene at the pointer.
949 
950     It is such a function that generates initialization events, entry,
951     transferring the context to the scene and causing the corresponding
952     events to lose the context.
953 
954     Params:
955         scene = Scene heir.
956     +/
957     void gotoin(Scene scene) @trusted
958     in(hasScene(scene))
959     do
960     {
961         _previous = current;
962 
963         if (current !is null)
964         {
965             if (current in LeaveFunctions)
966             {
967                 foreach (fun; LeaveFunctions[current])
968                 {
969                     fun();
970                 }
971             }
972 
973             foreach (instance; current.list())
974             {
975                 if (instance in ILeaveFunctions)
976                 {
977                     foreach (fun; ILeaveFunctions[instance])
978                     {
979                         fun();
980                     }
981                 }
982             }
983         }
984 
985         if (current !is null)
986         {
987             Instance[] persistents;
988 
989             foreach (instance; _previous.list())
990             {
991                 if (instance.persistent)
992                     persistents ~= instance;
993             }
994 
995             foreach (e; persistents)
996             {
997                 auto threadID = e.threadid;
998                 current.instanceDestroy!InScene(e, false);
999 
1000                 if (scene.isThreadExists(threadID))
1001                     scene.add(e,threadID);
1002                 else
1003                     scene.add(e);
1004             }
1005         }
1006 
1007         _initable = scene;
1008 
1009         if (!scene.isInit)
1010         {
1011             if (scene in InitFunctions)
1012             {
1013                 foreach (fun; InitFunctions[scene])
1014                 {
1015                     fun();
1016                 }
1017             }
1018 
1019             foreach (instance; scene.list())
1020             {
1021                 if (instance in IInitFunctions)
1022                 {
1023                     foreach (fun; IInitFunctions[instance])
1024                     {
1025                         fun();
1026                     }
1027                 }
1028             }
1029 
1030             scene.isInit = true;
1031         }else
1032         {
1033             if (scene in RestartFunctions)
1034             {
1035                 foreach (fun; RestartFunctions[scene])
1036                 {
1037                     fun();
1038                 }
1039             }
1040 
1041             foreach (instance; scene.list())
1042             {
1043                 if (instance in IRestartFunctions)
1044                 {
1045                     foreach (fun; IRestartFunctions[instance])
1046                     {
1047                         fun();
1048                     }
1049                 }
1050             }
1051         }
1052 
1053         if (scene in EntryFunctions)
1054         {
1055             foreach(fun; EntryFunctions[scene])
1056             {
1057                 fun();
1058             }
1059         }
1060 
1061         foreach (instance; scene.list())
1062         {
1063             if (instance in IEntryFunctions)
1064             {
1065                 foreach (fun; IEntryFunctions[instance])
1066                 {
1067                     fun();
1068                 }
1069             }
1070         }
1071 
1072         _initable = null;
1073 
1074         _current = scene;
1075     }
1076 
1077     /++
1078     Calling the game launch event.
1079 
1080     Should be called before all events, before the beginning of the
1081     cycle of life.
1082     +/
1083     void callGameStart() @trusted
1084     {
1085         foreach (scene; scenes)
1086         {
1087             if (scene in GameStartFunctions)
1088             {
1089                 foreach (fun; GameStartFunctions[scene])
1090                 {
1091                     fun();
1092                 }
1093             }
1094 
1095             foreach (instance; scene.list())
1096             {
1097                 if (instance.active && !instance.onlyDraw)
1098                 {
1099                     if (instance in IGameStartFunctions)
1100                     {
1101                         foreach (fun; IGameStartFunctions[instance])
1102                         {
1103                             fun();
1104                         }
1105                     }
1106                 }
1107             }
1108         }
1109     }
1110 
1111     /++
1112     Game completion call events (successful).
1113     The unsuccessful event should raise the `onError` event.
1114     +/
1115     void callGameExit() @trusted
1116     {
1117         foreach (scene; scenes)
1118         {
1119             if (scene in GameExitFunctions)
1120             {
1121                 foreach (fun; GameExitFunctions[scene])
1122                 {
1123                     fun();
1124                 }
1125             }
1126 
1127             foreach (instance; scene.list())
1128             {
1129                 if (instance.active && !instance.onlyDraw)
1130                 {
1131                     if (instance in IGameExitFunctions)
1132                     {
1133                         foreach (fun; IGameExitFunctions[instance])
1134                         {
1135                             fun();
1136                         }
1137                     }
1138                 }
1139             }
1140         }
1141     }
1142 
1143     /++
1144     Triggering an emergency event.
1145 
1146     Does not terminate the game, should be called on exceptions. After that,
1147     the programmer himself decides what to do next (if he implements his own
1148     life cycle). Called usually on `scope (failure)`, however, it will not
1149     throw a specific exception.
1150     +/
1151     void callOnError() @trusted
1152     {
1153         if (current !is null)
1154         {
1155             if (current in OnErrorFunctions)
1156             {
1157                 foreach (fun; OnErrorFunctions[current])
1158                 {
1159                     fun();
1160                 }
1161             }
1162 
1163             foreach (instance; current.list())
1164             {
1165                 if (instance.active && !instance.onlyDraw)
1166                 {
1167                     if (instance in IOnErrorFunctions)
1168                     {
1169                         foreach (fun; IOnErrorFunctions[instance])
1170                         {
1171                             fun();
1172                         }
1173                     }
1174                 }
1175             }
1176         }
1177     }
1178 
1179     /++
1180     Calling a game step. Should always be called during a loop step in an
1181     exception when the thread is suspended.
1182 
1183     Params:
1184         thread = Thread identificator.
1185         rend   = Renderer instance.
1186     +/
1187     void callStep(size_t thread, IRenderer rend) @trusted
1188     {
1189         if (current !is null)
1190         {
1191             current.worldCollision();
1192 
1193             if (thread == 0)
1194             if (current in StepFunctions)
1195             {
1196                 foreach (fun; StepFunctions[current])
1197                 {
1198                     fun();
1199                 }
1200             }
1201 
1202             if (current in StepThreadFunctions)
1203             if (thread in StepThreadFunctions[current])
1204             {
1205                 foreach (fun; StepThreadFunctions[current][thread])
1206                     fun();
1207             }
1208 
1209             foreach (instance; current.getThreadList(thread))
1210             {
1211                 if (instance.isDestroy)
1212                 {
1213                     current.instanceDestroy!InMemory(instance);
1214                     current.sort();
1215                     continue;
1216                 }
1217 
1218                 if (!instance.active || instance.onlyDraw) continue;
1219 
1220                 if (instance in IStepFunctions)
1221                 {
1222                     foreach (fun; IStepFunctions[instance])
1223                     {
1224                         fun();
1225                     }
1226                 }
1227 
1228                 foreach (component; instance.getComponents())
1229                 {
1230                     if (component in CStepFunctions)
1231                     {
1232                         foreach (fun; CStepFunctions[component])
1233                         {
1234                             fun();
1235                         }
1236                     }
1237                 }
1238             }
1239 
1240             foreach(instance; current.list())
1241             {
1242                 if (!instance.active || instance.onlyDraw) continue;
1243 
1244                 if (instance in IStepThreadFunctions)
1245                 if (thread in IStepThreadFunctions[instance])
1246                 {
1247                     foreach (fun; IStepThreadFunctions[instance][thread])
1248                         fun();
1249                 }
1250 
1251                 foreach (component; instance.getComponents())
1252                 {
1253                     if (component in CStepThreadFunctions)
1254                     if (thread in CStepThreadFunctions[component])
1255                     {
1256                         foreach(fun; CStepThreadFunctions[component][thread])
1257                         {
1258                             fun();
1259                         }
1260                     }
1261                 }
1262             }
1263         }
1264     }
1265 
1266     /++
1267     System event event for scenes and instances of the current context.
1268 
1269     Params:
1270         event = System event handler instance.
1271     +/
1272     void callEvent(EventHandler event) @trusted
1273     {
1274         if (current !is null)
1275         {
1276             if (current in EventHandleFunctions)
1277             {
1278                 foreach (fun; EventHandleFunctions[current])
1279                 {
1280                     fun(event);
1281                 }
1282             }
1283 
1284             foreach (instance; current.list())
1285             {
1286                 if (instance.active && !instance.onlyDraw)
1287                 {
1288                     if (instance in IEventHandleFunctions)
1289                     {
1290                         foreach(fun; IEventHandleFunctions[instance])
1291                         {
1292                             fun(event);
1293                         }
1294                     }
1295 
1296                     foreach (component; instance.getComponents())
1297                     {
1298                         if (component in CEventHandleFunctions)
1299                         {
1300                             foreach(fun; CEventHandleFunctions[component])
1301                             {
1302                                 fun(event);
1303                             }
1304                         }
1305                     }
1306                 }
1307             }
1308         }
1309     }
1310 
1311     /++
1312     Calling an event to render scenes and instances of the current context.
1313 
1314     Params:
1315         render = Render instance.
1316     +/
1317     void callDraw(IRenderer render) @trusted
1318     {
1319         import tida.vector;
1320 
1321         if (current !is null)
1322         {
1323             if (current in DrawFunctions)
1324             {
1325                 foreach (fun; DrawFunctions[current])
1326                 {
1327                     fun(render);
1328                 }
1329             }
1330 
1331             foreach (instance; current.getAssortedInstances())
1332             {
1333                 if (instance.active && instance.visible)
1334                 {
1335                     render.draw(instance.spriteDraw(), instance.position);
1336 
1337                     if (instance in IDrawFunctions)
1338                     {
1339                         foreach (fun; IDrawFunctions[instance])
1340                         {
1341                             fun(render);
1342                         }
1343                     }
1344 
1345                     foreach (component; instance.getComponents())
1346                     {
1347                         if (component in CDrawFunctions)
1348                         {
1349                             foreach (fun; CDrawFunctions[component])
1350                             {
1351                                 fun(render);
1352                             }
1353                         }
1354                     }
1355                 }
1356             }
1357         }
1358     }
1359 
1360     /// Free memory.
1361     void free() @safe
1362     {
1363         _scenes = null;
1364     }
1365 
1366     ~this() @safe
1367     {
1368         free();
1369     }
1370 }