Leviathan  0.8.0.0
Leviathan game engine
Engine.cpp
Go to the documentation of this file.
1 // ------------------------------------ //
2 #include "Engine.h"
3 
10 #include "Common/Types.h"
11 #include "Editor/Editor.h"
12 #include "Editor/Importer.h"
13 #include "Entities/GameWorld.h"
15 #include "Events/EventHandler.h"
16 #include "FileSystem.h"
17 #include "GUI/GuiManager.h"
18 #include "GlobalCEFHandler.h"
19 #include "Handlers/IDFactory.h"
26 #include "Rendering/Graphics.h"
27 #include "Script/Console.h"
28 #include "Sound/SoundDevice.h"
31 #include "Threading/QueuedTask.h"
33 #include "TimeIncludes.h"
35 #include "Utility/Random.h"
36 #include "Window.h"
37 
38 #include "utf8.h"
39 
40 #ifdef LEVIATHAN_USES_LEAP
41 #include "Leap/LeapManager.h"
42 #endif
43 
44 #ifdef LEVIATHAN_USING_SDL2
45 #include <SDL.h>
46 #endif
47 
48 #include "boost/program_options.hpp"
49 
50 #include <chrono>
51 #include <future>
52 
53 using namespace Leviathan;
54 using namespace std;
55 // ------------------------------------ //
57 static thread_local int MainThreadMagic = 0;
58 constexpr auto THREAD_MAGIC = 42;
59 
61 static std::atomic<int> WindowNameCounter = {1};
62 
64 {
65  // This makes sure that uninitialized engine will have at least some last frame time //
67 
68  instance = this;
69 }
70 
72 {
73  if(instance == this)
74  instance = nullptr;
75 
76  _ConsoleInput.reset();
77 }
78 
80 
82 {
83  return instance;
84 }
85 
87 {
88  return instance;
89 }
90 
92 {
93  return MainThreadMagic == THREAD_MAGIC;
94 }
95 // ------------------------------------ //
97  AppDef* definition, NETWORKED_TYPE ntype, NetworkInterface* packethandler)
98 {
99  GUARD_LOCK();
100 
102 
103  // Get the time, for monitoring how long loading takes //
104  auto InitStartTime = Time::GetTimeMs64();
105 
106  // Store parameters //
107  Define = definition;
108 
109  IsClient = ntype == NETWORKED_TYPE::Client;
110 
111  // Create all the things //
112 
114 
116 
117  // Create threading facilities //
119  if(!_ThreadingManager->Init()) {
120 
121  Logger::Get()->Error("Engine: Init: cannot start threading");
122  return false;
123  }
124 
125  // Create the randomizer //
126  MainRandom = new Random((int)InitStartTime);
128 
129  // Console might be the first thing we want //
130  if(!NoSTDInput) {
131 
132  _ConsoleInput = std::make_unique<ConsoleInput>();
133 
134  if(!_ConsoleInput->Init(
135  std::bind(&Engine::_ReceiveConsoleInput, this, std::placeholders::_1),
136  NoGui ? true : false)) {
137  Logger::Get()->Error("Engine: Init: failed to read stdin, perhaps pass --nocin");
138  return false;
139  }
140  }
141 
142  if(NoGui) {
143 
144  // Tell window title //
145  Logger::Get()->Write(
146  "// ----------- " + Define->GetWindowDetails().Title + " ----------- //");
147  }
148 
149 
150  // We could immediately receive a remote console request so this should be
151  // ready when networking is started
153 
154  // We want to send a request to the master server as soon as possible //
155  {
156  Lock lock(NetworkHandlerLock);
157 
158  _NetworkHandler = new NetworkHandler(ntype, packethandler);
159 
161  }
162 
163  // These should be fine to be threaded //
164 
165  // File change listener //
167  if(!_ResourceRefreshHandler->Init()) {
168 
169  Logger::Get()->Error("Engine: Init: cannot start resource monitor");
170  return false;
171  }
172 
173  // Data storage //
174  Mainstore = new DataStore(true);
175  if(!Mainstore) {
176 
177  Logger::Get()->Error("Engine: Init: failed to create main data store");
178  return false;
179  }
180 
181  // Search data folder for files //
182  MainFileHandler = new FileSystem();
183  if(!MainFileHandler) {
184 
185  Logger::Get()->Error("Engine: Init: failed to create FileSystem");
186  return false;
187  }
188 
189  if(!MainFileHandler->Init(Logger::Get())) {
190 
191  Logger::Get()->Error("Engine: Init: failed to init FileSystem");
192  return false;
193  }
194 
195  // File parsing //
197 
198  // Main program wide event dispatcher //
199  MainEvents = new EventHandler();
200  if(!MainEvents) {
201 
202  Logger::Get()->Error("Engine: Init: failed to create MainEvents");
203  return false;
204  }
205 
206  if(!MainEvents->Init()) {
207 
208  Logger::Get()->Error("Engine: Init: failed to init MainEvents");
209  return false;
210  }
211 
212  // Check is threading properly started //
213  if(!_ThreadingManager->CheckInit()) {
214 
215  Logger::Get()->Error("Engine: Init: threading start failed");
216  return false;
217  }
218 
219  // create script interface before renderer //
220  std::promise<bool> ScriptInterfaceResult;
221 
222  // Ref is OK to use since this task finishes before this function //
223  _ThreadingManager->QueueTask(std::make_shared<QueuedTask>(std::bind<void>(
224  [](std::promise<bool>& returnvalue, Engine* engine) -> void {
225  try {
226  engine->MainScript = new ScriptExecutor();
227  } catch(const Exception&) {
228 
229  Logger::Get()->Error("Engine: Init: failed to create ScriptInterface");
230  returnvalue.set_value(false);
231  return;
232  }
233 
234  // create console after script engine //
235  engine->MainConsole = new ScriptConsole();
236  if(!engine->MainConsole) {
237 
238  Logger::Get()->Error("Engine: Init: failed to create ScriptConsole");
239  returnvalue.set_value(false);
240  return;
241  }
242 
243  if(!engine->MainConsole->Init(engine->MainScript)) {
244 
245  Logger::Get()->Error("Engine: Init: failed to initialize Console, "
246  "continuing anyway");
247  }
248 
249  engine->_GameModuleLoader = std::make_unique<GameModuleLoader>();
250  engine->_GameModuleLoader->Init();
251 
252  if(!engine->NoGui) {
253  // measuring //
254  engine->RenderTimer = new RenderingStatistics();
255  if(!engine->RenderTimer) {
256  Logger::Get()->Error("Engine: Init: failed to create RenderingStatistics");
257 
258  returnvalue.set_value(false);
259  return;
260  }
261  }
262 
263  returnvalue.set_value(true);
264  },
265  std::ref(ScriptInterfaceResult), this)));
266 
267  // Check if we don't want a window //
268  if(NoGui) {
269 
270  Logger::Get()->Info("Engine: Init: starting in console mode "
271  "(won't allocate graphical objects) ");
272 
273  if(!_ConsoleInput->IsAttachedToConsole()) {
274 
275  Logger::Get()->Error(
276  "Engine: Init: in nogui mode and no input terminal connected, "
277  "quitting");
278  return false;
279  }
280 
282 
283  } else {
284 
285  ObjectFileProcessor::LoadValueFromNamedVars<int>(
286  Define->GetValues(), "MaxFPS", FrameLimit, 144, Logger::Get(), "Graphics: Init:");
287 
288  Graph = new Graphics();
289  }
290 
291  // We need to wait for all current tasks to finish //
293 
294  // Check return values //
295  if(!ScriptInterfaceResult.get_future().get()) {
296 
297  Logger::Get()->Error("Engine: Init: one or more queued tasks failed");
298  return false;
299  }
300 
301  // We can queue some more tasks //
302  // create leap controller //
303 #ifdef LEVIATHAN_USES_LEAP
304 
305  // Disable leap if in non-gui mode //
306  if(NoGui)
307  NoLeap = true;
308 
309  std::thread leapinitthread;
310  if(!NoLeap) {
311 
312  Logger::Get()->Info("Engine: will try to create Leap motion connection");
313 
314  // Seems that std::threads are joinable when constructed with default constructor
315  leapinitthread = std::thread(std::bind<void>(
316  [](Engine* engine) -> void {
317  engine->LeapData = new LeapManager(engine);
318  if(!engine->LeapData) {
319  Logger::Get()->Error("Engine: Init: failed to create LeapManager");
320  return;
321  }
322  // try here just in case //
323  try {
324  if(!engine->LeapData->Init()) {
325 
326  Logger::Get()->Info(
327  "Engine: Init: No Leap controller found, not using one");
328  }
329  } catch(...) {
330  // threw something //
331  Logger::Get()->Error(
332  "Engine: Init: Leap threw something, even without leap "
333  "this shouldn't happen; continuing anyway");
334  }
335  },
336  this));
337  }
338 #endif
339 
340 
341  // sound device //
342  if(!NoGui) {
343  Sound = new SoundDevice();
344 
345  if(!Sound) {
346  Logger::Get()->Error("Engine: Init: failed to create Sound");
347  return false;
348  }
349 
350  if(!Sound->Init()) {
351 
352  Logger::Get()->Error(
353  "Engine: Init: failed to init SoundDevice. Continuing anyway");
354  }
355  }
356 
357  if(!NoGui) {
358  if(!Graph) {
359 
360  Logger::Get()->Error("Engine: Init: failed to create instance of Graphics");
361  return false;
362  }
363 
364  // call init //
365  if(!Graph->Init(definition)) {
366  Logger::Get()->Error("Failed to init Engine, Init graphics failed! Aborting");
367  return false;
368  }
369 
370  // Create window //
371  GraphicalEntity1 = new Window(Graph, definition);
372  }
373 
374 #ifdef LEVIATHAN_USES_LEAP
375  // We can probably assume here that leap creation has stalled if the thread is running //
376  if(!NoLeap) {
377 
378  auto start = WantedClockType::now();
379 
380  while(leapinitthread.joinable()) {
381 
382  auto elapsed = WantedClockType::now() - start;
383 
384  if(elapsed > std::chrono::milliseconds(150)) {
385 
386  Logger::Get()->Warning("LeapController creation would have stalled the game!");
387  Logger::Get()->Write("TODO: allow increasing wait period");
388  leapinitthread.detach();
389  break;
390  }
391 
392  std::this_thread::sleep_for(std::chrono::milliseconds(5));
393  }
394  }
395 #endif
396 
397  const auto timeNow = Time::GetTimeMs64();
398 
399  LOG_INFO("Engine init took " + Convert::ToString(timeNow - InitStartTime) + " ms");
400 
401  PostLoad();
402 
403  const auto timeAfterPostLoad = Time::GetTimeMs64();
404 
405  if(timeAfterPostLoad - timeNow > 5)
406  LOG_INFO("PostLoad took " + Convert::ToString(timeAfterPostLoad - timeNow) + " ms");
407 
408 
409  return true;
410 }
411 
413 {
414  // increase start count //
415  int startcounts = 0;
416 
417  if(Mainstore->GetValueAndConvertTo<int>("StartCount", startcounts)) {
418  // increase //
419  Mainstore->SetValue("StartCount", new VariableBlock(new IntBlock(startcounts + 1)));
420  } else {
421 
422  Mainstore->AddVar(
423  std::make_shared<NamedVariableList>("StartCount", new VariableBlock(1)));
424 
425  // set as persistent //
426  Mainstore->SetPersistance("StartCount", true);
427  }
428 
429  // Makes sure commands don't fail if they use some time stuff
430  ClearTimers();
431 
433 
434  // Run startup command line //
436 
437  // Run queued imports
438  if(!QueuedImports.empty()) {
439  for(const auto& importer : QueuedImports) {
440  try {
441  if(!importer->Run()) {
442 
443  LOG_ERROR("An import operation failed");
444  }
445  } catch(const Exception& e) {
446  LOG_ERROR("An exception happened in importer:");
447  e.PrintToLog();
448  }
449  }
450 
451  QueuedImports.clear();
452  LOG_INFO("Marking as closing after processing imports");
453  MarkQuit();
454  }
455 
456  // Makes the time next tick happens good
457  ClearTimers();
458 }
459 // ------------------------------------ //
461 {
462  GUARD_LOCK();
463 
465  return;
466 
467  PreReleaseWaiting = true;
468  // This will stay true until the end of times //
469  PreReleaseCompleted = true;
470 
471  // Stop command handling first //
472  if(_ConsoleInput) {
473 
474  _ConsoleInput->Release(false);
475  Logger::Get()->Info("Successfully stopped command handling");
476  }
477 
478  // Close all editors
479  OpenedEditors.clear();
480 
481  // Automatically destroy input sources //
483 
484  // Then kill the network //
485  {
486  Lock lock(NetworkHandlerLock);
487 
489  }
490 
491  // Let the game release it's resources //
493 
494  // Close remote console //
496 
497  // Close all connections //
498  {
499  Lock lock(NetworkHandlerLock);
500 
502  }
503 
505 
506  // Set worlds to empty //
507  {
508  Lock lock(GameWorldsLock);
509 
510  for(auto iter = GameWorlds.begin(); iter != GameWorlds.end(); ++iter) {
511  // Set all objects to release //
512  (*iter)->MarkForClear();
513  }
514  }
515 
516  // Set tasks to a proper state //
519 
520  Logger::Get()->Info("Engine: prerelease done, waiting for a tick");
521 }
522 
523 void Engine::Release(bool forced)
524 {
525  GUARD_LOCK();
526 
527  if(!forced)
528  LEVIATHAN_ASSERT(PreReleaseDone, "PreReleaseDone must be done before actual release!");
529 
530  // Force garbase collection //
531  if(MainScript)
533 
534  // Make windows clear their stored objects //
535  for(size_t i = 0; i < AdditionalGraphicalEntities.size(); i++) {
536 
537  AdditionalGraphicalEntities[i]->UnlinkAll();
538  }
539 
540  // Finally the main window //
541  if(GraphicalEntity1) {
542 
544  }
545 
546  // Destroy worlds //
547  {
548  Lock lock(GameWorldsLock);
549 
550  while(GameWorlds.size()) {
551 
552  GameWorlds[0]->Release();
553  GameWorlds.erase(GameWorlds.begin());
554  }
555  }
556 
557  if(_NetworkHandler)
559 
560  // Wait for tasks to finish //
561  if(!forced)
563 
564  // Destroy windows //
565  for(size_t i = 0; i < AdditionalGraphicalEntities.size(); i++) {
566 
568  }
569 
571 
573 
574 #ifdef LEVIATHAN_USES_LEAP
575  SAFE_RELEASEDEL(LeapData);
576 #endif
577 
578  // Console needs to be released before script release //
580 
581  _GameModuleLoader.reset();
582 
584 
585  // Save at this point (just in case it crashes before exiting) //
586  Logger::Get()->Save();
587 
588 
590 
593 
594  // If graphics aren't unregistered crashing will occur //
596 
597  // Stop threads //
599 
601 
603  // delete randomizer last, for obvious reasons //
605 
608 
609  // clears all running timers that might have accidentally been left running //
611 
612  // safe to delete this here //
614 
616 
617  Logger::Get()->Write("Goodbye cruel world!");
618 }
619 // ------------------------------------ //
621 {
622  // CEF events (Also on windows as multi_threaded_message_loop makes rendering harder)
624 
625  SDL_Event event;
626  while(SDL_PollEvent(&event)) {
627 
628  switch(event.type) {
629  case SDL_QUIT:
630  LOG_INFO("SDL_QUIT received, marked as closing");
631  MarkQuit();
632  break;
633 
634  case SDL_KEYDOWN: {
635  Window* win = GetWindowFromSDLID(event.key.windowID);
636 
637  if(win) {
638 
639  // LOG_WRITE("SDL_KEYDOWN: " + Convert::ToString(event.key.keysym.sym));
640 
641  // Core engine functionality keys
642  switch(event.key.keysym.sym) {
643  case SDLK_F10: {
644  // Editor key pressed
645  LOG_INFO("Editor key pressed");
647  break;
648  }
649  default: win->InjectKeyDown(event);
650  }
651  }
652  break;
653  }
654  case SDL_KEYUP: {
655  Window* win = GetWindowFromSDLID(event.key.windowID);
656 
657  if(win) {
658 
659  // LOG_WRITE("SDL_KEYUP: " + Convert::ToString(event.key.keysym.sym));
660  win->InjectKeyUp(event);
661  }
662 
663  break;
664  }
665  case SDL_TEXTINPUT: {
666  Window* win = GetWindowFromSDLID(event.text.windowID);
667 
668  if(win) {
669 
670  const auto text = std::string(event.text.text);
671 
672  // LOG_WRITE("TextInput: " + text);
673 
674  std::vector<uint32_t> codepoints;
675 
677  std::begin(text), std::end(text), std::back_inserter(codepoints));
678 
679  // LOG_WRITE("Codepoints(" + Convert::ToString(codepoints.size()) + "): ");
680  // for(auto codepoint : codepoints)
681  // LOG_WRITE(" " + Convert::ToString(codepoint));
682  for(auto codepoint : codepoints) {
683 
684  win->InjectCodePoint(event);
685  }
686  }
687 
688  break;
689  }
690  // TODO: implement this
691  // case SDL_TEXTEDITING: (https://wiki.libsdl.org/Tutorials/TextInput)
692  case SDL_MOUSEBUTTONDOWN: {
693  Window* win = GetWindowFromSDLID(event.button.windowID);
694 
695  if(win)
696  win->InjectMouseButtonDown(event);
697 
698  break;
699  }
700 
701  case SDL_MOUSEBUTTONUP: {
702  Window* win = GetWindowFromSDLID(event.button.windowID);
703 
704  if(win)
705  win->InjectMouseButtonUp(event);
706 
707  break;
708  }
709 
710  case SDL_MOUSEMOTION: {
711  Window* win = GetWindowFromSDLID(event.motion.windowID);
712 
713  if(win)
714  win->InjectMouseMove(event);
715 
716  break;
717  }
718 
719  case SDL_MOUSEWHEEL: {
720  Window* win = GetWindowFromSDLID(event.motion.windowID);
721 
722  if(win)
723  win->InjectMouseWheel(event);
724 
725  break;
726  }
727 
728  case SDL_WINDOWEVENT: {
729  switch(event.window.event) {
730 
731  case SDL_WINDOWEVENT_RESIZED: {
732  Window* win = GetWindowFromSDLID(event.window.windowID);
733 
734  if(win) {
735 
736  int32_t width, height;
737  win->GetSize(width, height);
738 
739  LOG_INFO("SDL window resize: " + Convert::ToString(width) + "x" +
740  Convert::ToString(height));
741 
742  win->OnResize(width, height);
743  }
744 
745  break;
746  }
747  case SDL_WINDOWEVENT_CLOSE: {
748  LOG_INFO("SDL window close");
749 
750  Window* win = GetWindowFromSDLID(event.window.windowID);
751 
752  // Detect closed windows //
753  if(win == GraphicalEntity1) {
754  // Window closed //
756  }
757 
758  for(size_t i = 0; i < AdditionalGraphicalEntities.size(); i++) {
759  if(AdditionalGraphicalEntities[i] == win) {
760 
762  break;
763  }
764  }
765 
766  break;
767  }
768  case SDL_WINDOWEVENT_FOCUS_GAINED: {
769  Window* win = GetWindowFromSDLID(event.window.windowID);
770 
771  if(win)
772  win->OnFocusChange(true);
773 
774  break;
775  }
776  case SDL_WINDOWEVENT_FOCUS_LOST: {
777  Window* win = GetWindowFromSDLID(event.window.windowID);
778 
779  if(win)
780  win->OnFocusChange(false);
781 
782  break;
783  }
784  }
785  }
786  }
787  }
788 
789  // CEF needs to be let handle the keyboard events now to make sure that they can be
790  // dispatched to further on listeners
792 
793  // Reset input states //
794  if(GraphicalEntity1) {
795 
796  // TODO: fix initial mouse position being incorrect
798  }
799 
800  for(auto iter = AdditionalGraphicalEntities.begin();
801  iter != AdditionalGraphicalEntities.end(); ++iter) {
802  (*iter)->InputEnd();
803  }
804 }
805 
807 {
808  if(GraphicalEntity1 && GraphicalEntity1->GetSDLID() == sdlid) {
809  return GraphicalEntity1;
810  }
811 
812  for(auto iter = AdditionalGraphicalEntities.begin();
813  iter != AdditionalGraphicalEntities.end(); ++iter) {
814  if((*iter)->GetSDLID() == sdlid) {
815 
816  return *iter;
817  }
818  }
819 
820  return nullptr;
821 }
822 // ------------------------------------ //
824 {
825  // Always try to update networking //
826  {
827  Lock lock(NetworkHandlerLock);
828 
829  if(_NetworkHandler)
831  }
832 
833  // And handle invokes //
834  ProcessInvokes();
835 
836  const auto now = Time::GetCurrentTimePoint();
837 
838  GUARD_LOCK();
839 
840  SecondDuration elapsed = now - LastTickTime;
841 
842  if(elapsed.count() <= 0.f) {
843  // Time passed is too short, everything will break if our step is 0, so try again
844  // very shortly
845  LOG_INFO("Trying to run Update before any (detectable) time has passed, skipping");
846  return 0.f;
847  }
848 
849  if(elapsed > SecondDuration(1)) {
850  LOG_ERROR("Game is lagging! Time since last update: " +
851  std::to_string(elapsed.count()) + "s. Capping it at one second.");
852  elapsed = SecondDuration(1);
853  }
854 
855  bool frameLimited = FrameLimit >= 0 && FrameLimit < 1000;
856 
857  PreciseSecondDuration frameInterval;
858 
859  // Update limiter
860  // This is now a much simpler limiter based on needing to have some time elapsed since last
861  // tick
862  if(frameLimited) {
863 
864  frameInterval = PreciseSecondDuration(1.0 / FrameLimit);
865 
866  if(elapsed < frameInterval) {
867  return SecondDuration(frameInterval - elapsed).count();
868  }
869  }
870 
871  // Update should happen
872 
873  LastTickTime = now;
874 
875  // Tick first
876  Tick(elapsed.count());
877 
878  const auto tickDuration = Time::GetCurrentTimePoint() - LastTickTime;
879 
880  TickTime = std::chrono::duration_cast<MillisecondDuration>(tickDuration).count();
881 
882  // And then render (this skips rendering in headless mode)
883  RenderFrame(elapsed.count());
884 
885  if(frameLimited) {
886  return std::max(
887  SecondDuration(LastTickTime - Time::GetCurrentTimePoint() - frameInterval).count(),
888  0.f);
889  } else {
890  // No update rate limit. No sleep should happen before the next update
891  return 0.f;
892  }
893 }
894 
895 void Engine::Tick(float elapsed)
896 {
897  if(PreReleaseWaiting) {
898 
899  PreReleaseWaiting = false;
900  PreReleaseDone = true;
901 
902  Logger::Get()->Info("Engine: performing final release tick");
903 
904  // Call last tick event //
905 
906  return;
907  }
908 
909  TickCount++;
910 
911  // Update input //
912 #ifdef LEVIATHAN_USES_LEAP
913  if(LeapData)
914  LeapData->OnTick(TimePassed);
915 #endif
916 
917  // sound tick //
918  if(Sound)
919  Sound->Tick(elapsed);
920 
921  if(!NoGui) {
922  // update windows //
923  if(GraphicalEntity1)
924  GraphicalEntity1->Tick(elapsed);
925 
926  for(size_t i = 0; i < AdditionalGraphicalEntities.size(); i++) {
927 
928  AdditionalGraphicalEntities[i]->Tick(elapsed);
929  }
930  }
931 
932 
933  // Update worlds //
934  {
935  Lock lock(GameWorldsLock);
936 
937  // This will also update physics //
938  auto end = GameWorlds.end();
939  for(auto iter = GameWorlds.begin(); iter != end; ++iter) {
940 
941  (*iter)->Tick(elapsed);
942  }
943  }
944 
945  // Some dark magic here //
946  if(TickCount % 25 == 0) {
947  // update values
951  // TODO: having the max tick time of the past second, would also be nice
952 
953  if(!NoGui) {
954  // send updated rendering statistics //
956  }
957  }
958 
959  // Update file listeners //
962 
963  // Send the tick event //
964  if(MainEvents)
966 
967  // Call the default app tick //
968  Owner->Tick(elapsed);
969 }
970 
972 {
973  GUARD_LOCK();
974 
977 
978  ClearTimers();
979 
980  Logger::Get()->Info("Engine: PreFirstTick: everything fine to start running");
981 }
982 // ------------------------------------ //
983 void Engine::RenderFrame(float elapsed)
984 {
985  // We want to totally ignore this if we are in headless mode
986  if(NoGui)
987  return;
988 
989  FrameCount++;
990 
991  // This is needed for the statistics to work correctly but this is no longer used to track
992  // if we can render or not
993  int unused;
995 
996  // advanced statistic start monitoring //
998 
1000 
1001  bool shouldrender = false;
1002 
1003  // Render //
1004  if(GraphicalEntity1 && GraphicalEntity1->Render(elapsed))
1005  shouldrender = true;
1006 
1007  for(size_t i = 0; i < AdditionalGraphicalEntities.size(); i++) {
1008 
1009  if(AdditionalGraphicalEntities[i]->Render(elapsed))
1010  shouldrender = true;
1011  }
1012 
1013  // guard.unlock();
1014  if(shouldrender)
1015  Graph->Frame();
1016 
1017  // guard.lock();
1018 
1019  // advanced statistics frame has ended //
1021 }
1022 // ------------------------------------ //
1024 {
1025  LEVIATHAN_ASSERT(!NoGui, "really shouldn't try to screenshot in text-only mode");
1026  GUARD_LOCK();
1027 
1028  const string fileprefix = MainFileHandler->GetDataFolder() + "Screenshots/Captured_frame_";
1029 
1030  GraphicalEntity1->SaveScreenShot(fileprefix);
1031 }
1032 
1034 {
1035  int openwindows = 0;
1036 
1037  // If we are in text only mode always return 1 //
1038  if(NoGui)
1039  return 1;
1040 
1041  // TODO: should there be an IsOpen method?
1042  if(GraphicalEntity1)
1043  openwindows++;
1044 
1045  for(size_t i = 0; i < AdditionalGraphicalEntities.size(); i++) {
1046 
1048  openwindows++;
1049  }
1050 
1051  return openwindows;
1052 }
1053 // ------------------------------------ //
1055 {
1056  if(window == GraphicalEntity1) {
1057  return true;
1058  }
1059 
1060  for(Window* openWindow : AdditionalGraphicalEntities) {
1061  if(openWindow == window) {
1062  return true;
1063  }
1064  }
1065 
1066  return false;
1067 }
1068 
1070 {
1072 
1073  AppDef winparams;
1074 
1076  "Leviathan Window " + std::to_string(++WindowNameCounter), 1280, 720, "no",
1077  // Multiple vsyncs cause issues (or they can cause issues, sometimes it is fine)
1078  /* Define->GetWindowDetails().VSync */ false,
1079  // Opens on same display as the other window
1080  // TODO: open on next display
1082 #ifdef _WIN32
1083  Define->GetWindowDetails().Icon,
1084 #endif
1085  nullptr));
1086 
1087  auto newwindow = std::make_unique<Window>(Graph, &winparams);
1088 
1089  AdditionalGraphicalEntities.push_back(newwindow.get());
1090 
1091  return newwindow.release();
1092 }
1093 
1095 {
1096  if(!window)
1097  return false;
1098 
1099  if(IsValidWindow(window)) {
1100 
1101  ReportClosedWindow(window);
1102  return true;
1103  } else {
1104  return false;
1105  }
1106 }
1107 
1109 {
1110  windowentity->UnlinkAll();
1111 
1112  if(GraphicalEntity1 == windowentity) {
1113 
1115  return;
1116  }
1117 
1118  for(size_t i = 0; i < AdditionalGraphicalEntities.size(); i++) {
1119 
1120  if(AdditionalGraphicalEntities[i] == windowentity) {
1121 
1124 
1125  return;
1126  }
1127  }
1128 
1129  // Didn't find the target //
1130  Logger::Get()->Error("Engine: couldn't find closing Window");
1131 }
1132 // ------------------------------------ //
1133 DLLEXPORT void Engine::OpenEditorWindow(Window* useexistingwindow /*= nullptr*/)
1134 {
1136 
1137  if(useexistingwindow && !IsValidWindow(useexistingwindow)) {
1138 
1139  LOG_WARNING("Engine: OpenEditorWindow: invalid window given, defaulting to opening a "
1140  "new window");
1141  useexistingwindow = nullptr;
1142  }
1143 
1144  if(!useexistingwindow) {
1145  useexistingwindow = OpenNewWindow();
1146  }
1147 
1148 
1149  OpenedEditors.emplace_back(std::make_unique<Editor::Editor>(useexistingwindow, this));
1150 }
1151 
1153 {
1154  if(OpenedEditors.empty()) {
1155 
1156  OpenEditorWindow();
1157  return;
1158  }
1159 
1160  OpenedEditors.front()->BringToFront();
1161 }
1162 // ------------------------------------ //
1164 {
1165  if(Owner)
1166  Owner->MarkAsClosing();
1167 }
1168 // ------------------------------------ //
1169 DLLEXPORT void Engine::Invoke(const std::function<void()>& function)
1170 {
1171  RecursiveLock lock(InvokeLock);
1172  InvokeQueue.push_back(function);
1173 }
1174 
1176 {
1177  RecursiveLock lock(InvokeLock);
1178 
1179  while(!InvokeQueue.empty()) {
1180 
1181  const auto& func = InvokeQueue.front();
1182 
1183  // Recursive mutex allows the invoke to call extra invokes
1184  func();
1185 
1186  InvokeQueue.pop_front();
1187  }
1188 }
1189 
1190 DLLEXPORT void Engine::RunOnMainThread(const std::function<void()>& function)
1191 {
1192  if(!IsOnMainThread()) {
1193 
1194  Invoke(function);
1195 
1196  } else {
1197 
1198  function();
1199  }
1200 }
1201 // ------------------------------------ //
1202 DLLEXPORT std::shared_ptr<GameWorld> Engine::CreateWorld(Window* owningwindow, int worldtype,
1203  const std::shared_ptr<PhysicsMaterialManager>& physicsMaterials,
1204  const WorldNetworkSettings& networking, int overrideid /*= -1*/)
1205 {
1206  std::shared_ptr<GameWorld> world;
1207  if(worldtype >= 1024) {
1208  // Standard world types
1210  static_cast<INBUILT_WORLD_TYPE>(worldtype), physicsMaterials, overrideid);
1211  } else {
1212  world =
1213  GameWorldFactory::Get()->CreateNewWorld(worldtype, physicsMaterials, overrideid);
1214  }
1215 
1216  if(!world) {
1217 
1218  LOG_ERROR("Engine: CreateWorld: factory failed to create a world of type: " +
1219  std::to_string(worldtype));
1220  return nullptr;
1221  }
1222 
1223  world->Init(networking, NoGui ? nullptr : Graph);
1224 
1225  if(owningwindow)
1226  owningwindow->LinkObjects(world);
1227 
1228  Lock lock(GameWorldsLock);
1229 
1230  GameWorlds.push_back(world);
1231  return GameWorlds.back();
1232 }
1233 
1234 DLLEXPORT void Engine::DestroyWorld(const shared_ptr<GameWorld>& world)
1235 {
1236  if(!world)
1237  return;
1238 
1239  // Release the world first //
1240  world->Release();
1241 
1242  // Then delete it //
1243  Lock lock(GameWorldsLock);
1244 
1245  auto end = GameWorlds.end();
1246  for(auto iter = GameWorlds.begin(); iter != end; ++iter) {
1247 
1248  if((*iter).get() == world.get()) {
1249 
1250  GameWorlds.erase(iter);
1251  return;
1252  }
1253  }
1254 }
1255 // ------------------------------------ //
1257 {
1259 
1260  Lock lock(GameWorldsLock);
1261 
1262  for(auto iter = GameWorlds.begin(); iter != GameWorlds.end(); ++iter) {
1263  }
1264 }
1265 // ------------------------------------ //
1267 {
1268  if(NoGui)
1269  return;
1270 
1271  // Register threads to use graphical objects //
1273 }
1274 // ------------------------------------ //
1276 {
1278 }
1279 
1280 // DLLEXPORT int Engine::GetCurrentTick() const
1281 // {
1282 // return TickCount;
1283 // }
1284 // ------------------------------------ //
1285 int TestCrash(int writenum)
1286 {
1287  volatile int* target = nullptr;
1288  (*target) = writenum;
1289 
1290  Logger::Get()->Write("It didn't crash...");
1291  return 42;
1292 }
1293 
1294 DLLEXPORT bool Engine::PassCommandLine(int argcount, char* args[])
1295 {
1296  namespace po = boost::program_options;
1297 
1298  std::vector<std::vector<std::string>> import;
1299  std::vector<std::string> cmds;
1300  // TODO: these could probably directly be read into the variables in this class
1301  bool nogui = false;
1302  bool noleap = false;
1303  bool nocin = false;
1304 
1305  bool crash = false;
1306 
1307  po::options_description desc("Engine Options");
1308  // clang-format off
1309  desc.add_options()
1310  ("import", po::value<std::vector<std::string>>()->multitoken(),
1311  "Import assets from source to destination")
1312  ("cmd", po::value<std::vector<std::string>>(&cmds)->multitoken(),
1313  "Run console commands after startup")
1314  ("nogui", po::bool_switch(&nogui), "Disable graphics")
1315  ("nocin", po::bool_switch(&nocin), "Disable stdin reading")
1316  ("noleap", po::bool_switch(&noleap), "Disable Leap Motion")
1317  ("noleap", po::bool_switch(&crash), "Crash for testing purposes")
1318  // We see CEF arguments here, we need to allow them
1319  ("no-sandbox", "CEF option")
1320  ("single-process", "CEF option")
1321  ("disable-gpu", "CEF option")
1322  ;
1323  // clang-format on
1324 
1325  // TODO: allow the game to add extra options here
1326 
1327  po::positional_options_description positional;
1328  positional.add("cmd", -1);
1329 
1330  // This was before added to PassedCommands.push_back(std::move(splitval));
1331  // but it would be better to make those actual flags
1332 
1333  po::variables_map vm;
1334 
1335  try {
1336  // The parsing is done in two steps here to add custom handling for the import option
1337  po::parsed_options parsed_options =
1338  po::command_line_parser(argcount, args).options(desc).positional(positional).run();
1339 
1340 
1341  // Read import option lists
1342  for(const po::option& option : parsed_options.options) {
1343  if(option.string_key == "import")
1344  import.push_back(option.value);
1345  }
1346 
1347  // Finish parsing
1348  po::store(parsed_options, vm);
1349  po::notify(vm);
1350 
1351  } catch(const po::error& e) {
1352  LOG_INFO("Engine: Command line: ");
1353  for(int i = 0; i < argcount; ++i) {
1354 
1355  LOG_WRITE("\t> " + (args[i] ? std::string(args[i]) : std::string()));
1356  }
1357 
1358  LOG_ERROR("Engine: parsing command line failed: " + std::string(e.what()));
1359 
1360  std::stringstream sstream;
1361  desc.print(sstream);
1362 
1363  LOG_WRITE(sstream.str());
1364 
1365  return false;
1366  }
1367 
1368  if(nogui) {
1369  NoGui = true;
1370  LOG_INFO("Engine starting in non-GUI mode");
1371  }
1372 
1373  if(nocin) {
1374  NoSTDInput = true;
1375  LOG_INFO("Engine not listening for terminal commands");
1376  }
1377 
1378  if(noleap) {
1379  NoLeap = true;
1380 
1381 #ifdef LEVIATHAN_USES_LEAP
1382  LOG_INFO("Engine starting with LeapMotion disabled");
1383 #endif
1384  }
1385 
1386  if(crash) {
1387  LOG_INFO("Engine testing crash handling");
1388  // TODO: write a file that disables crash handling
1389  // Make the log say something useful //
1390  Logger::Get()->Save();
1391 
1392  // Test crashing //
1393  TestCrash(12);
1394  }
1395 
1396  // // Coalesce commands
1397  // if(vm.count("console-commands")) {
1398  // }
1399 
1400  for(const std::string& command : cmds) {
1401  if(StringOperations::IsCharacterQuote(command.at(0))) {
1402 
1403  StringIterator itr(command);
1404 
1405  auto withoutquotes = itr.GetStringInQuotes<std::string>(QUOTETYPE_BOTH);
1406 
1407  if(withoutquotes) {
1408 
1409  QueuedConsoleCommands.push_back(std::move(withoutquotes));
1410 
1411  } else {
1412 
1413  LOG_WARNING("Engine: command in quotes is empty");
1414  }
1415 
1416  } else {
1417 
1418  QueuedConsoleCommands.push_back(std::make_unique<std::string>(command));
1419  }
1420  }
1421 
1422  for(const auto& group : import) {
1423 
1424  if(group.size() != 2) {
1425 
1426  LOG_ERROR("Import option needs two parameters, source and destination, parameter "
1427  "count: " +
1428  std::to_string(group.size()));
1429  return false;
1430  }
1431 
1432  QueuedImports.push_back(std::make_unique<Editor::Importer>(group[0], group[1]));
1433  }
1434 
1435  return true;
1436 }
1437 
1439 {
1440  StringIterator itr;
1441 
1442  // TODO: this does nothing
1443  // Iterate over the commands and process them //
1444  for(size_t i = 0; i < PassedCommands.size(); i++) {
1445 
1446  itr.ReInit(PassedCommands[i].get());
1447  // Skip the preceding '-'s //
1448  itr.SkipCharacters('-');
1449 
1450  // Get the command //
1451  auto firstpart = itr.GetUntilNextCharacterOrAll<string>(':');
1452 
1453  // Execute the wanted command //
1454  if(StringOperations::CompareInsensitive<string>(*firstpart, "RemoteConsole")) {
1455 
1456  // Get the next command //
1457  auto commandpart = itr.GetUntilNextCharacterOrAll<string>(L':');
1458 
1459  if(*commandpart == "CloseIfNone") {
1460  // Set the command //
1462  Logger::Get()->Info("Engine will close when no active/waiting remote console "
1463  "sessions");
1464 
1465  } else if(*commandpart == "OpenTo") {
1466  // Get the to part //
1467  auto topart = itr.GetStringInQuotes<string>(QUOTETYPE_BOTH);
1468 
1469  int token = 0;
1470 
1471  auto numberpart = itr.GetNextNumber<string>(DECIMALSEPARATORTYPE_NONE);
1472 
1473  if(numberpart->size() == 0) {
1474 
1475  Logger::Get()->Warning("Engine: ExecuteCommandLine: RemoteConsole: "
1476  "no token number provided");
1477  continue;
1478  }
1479  // Convert to a real number. Maybe we could see if the token is
1480  // complex enough here, but that isn't necessary
1481  token = Convert::StringTo<int>(*numberpart);
1482 
1483  if(token == 0) {
1484  // Invalid number? //
1485  Logger::Get()->Warning("Engine: ExecuteCommandLine: RemoteConsole: "
1486  "couldn't parse token number, " +
1487  *numberpart);
1488  continue;
1489  }
1490 
1491  // Create a connection (or potentially use an existing one) //
1492  shared_ptr<Connection> tmpconnection =
1494 
1495  // Tell remote console to open a command to it //
1496  if(tmpconnection) {
1497 
1498  _RemoteConsole->OfferConnectionTo(tmpconnection, "AutoOpen", token);
1499 
1500  } else {
1501  // Something funky happened... //
1502  Logger::Get()->Warning("Engine: ExecuteCommandLine: RemoteConsole: "
1503  "couldn't open connection to " +
1504  *topart + ", couldn't resolve address");
1505  }
1506 
1507  } else {
1508  // Unknown command //
1509  Logger::Get()->Warning("Engine: ExecuteCommandLine: unknown RemoteConsole "
1510  "command: " +
1511  *commandpart +
1512  ", whole argument: " + *PassedCommands[i]);
1513  }
1514  }
1515  }
1516 
1517 
1518  PassedCommands.clear();
1519 
1520  // Now we can set some things that require command line arguments //
1521  // _RemoteConsole might be NULL //
1522  if(_RemoteConsole)
1524 }
1525 // ------------------------------------ //
1527 {
1528  if(QueuedConsoleCommands.empty())
1529  return;
1530 
1531  if(!MainConsole) {
1532 
1533  LOG_FATAL("Engine: MainConsole has not been created before running command line "
1534  "passed commands");
1535  return;
1536  }
1537 
1538  LOG_INFO("Engine: Running PostStartup command line. Commands: " +
1540 
1541  for(auto& command : QueuedConsoleCommands) {
1542 
1543  LOG_INFO("Engine: Running \"" + *command + "\"");
1544  MainConsole->RunConsoleCommand(*command);
1545  }
1546 
1547  QueuedConsoleCommands.clear();
1548 }
1549 // ------------------------------------ //
1550 bool Engine::_ReceiveConsoleInput(const std::string& command)
1551 {
1552  Invoke([=]() {
1553  if(MainConsole) {
1554 
1555  MainConsole->RunConsoleCommand(command);
1556 
1557  } else {
1558 
1559  LOG_WARNING("No console handler attached, cannot run command");
1560  }
1561  });
1562 
1563  // Listening thread quits if PreReleaseWaiting is true
1564  return PreReleaseWaiting;
1565 }
1566 // ------------------------------------ //
DLLEXPORT bool IsOnMainThread() const
Returns true if called on the main thread.
Definition: Engine.cpp:91
static DLLEXPORT std::string GetDataFolder()
Definition: FileSystem.cpp:198
void _NotifyThreadsRegisterOgre()
Definition: Engine.cpp:1266
DLLEXPORT void SetDiscardConditionalTasks(bool discard)
Sets the task queuer to discard all conditional tasks.
ScriptExecutor * MainScript
Definition: Engine.h:313
virtual DLLEXPORT bool Init()
Sets up the work queue.
DLLEXPORT void MarkQuit()
Marks the owning application to quit.
Definition: Engine.cpp:1163
DLLEXPORT void PreRelease()
Sets objects ready to be released.
Definition: Engine.cpp:460
DLLEXPORT bool Init(AppDef *appdef)
Definition: Graphics.cpp:167
DLLEXPORT void Tick(float elapsed)
Class that represents a statically defined event.
Definition: Event.h:106
DLLEXPORT bool Render(float elapsed)
This function uses the LinkObjects function objects.
Definition: Window.cpp:300
DLLEXPORT void Write(const std::string &data) override
Definition: Logger.cpp:113
DLLEXPORT ~Engine()
Definition: Engine.cpp:71
DLLEXPORT void ClearTimers()
Clears physical timers.
Definition: Engine.cpp:1256
virtual DLLEXPORT void EnginePreShutdown()
DLLEXPORT void Invoke(const std::function< void()> &function)
Runs function on the main thread before the next tick.
Definition: Engine.cpp:1169
DLLEXPORT void GetSize(int32_t &width, int32_t &height) const
Definition: Window.cpp:896
DLLEXPORT void ShutdownCache()
Destroys the network cache permanently.
bool GetValueAndConvertTo(const std::string &name, T &receiver) const
Definition: DataStore.h:82
u32bit_iterator utf8to32(octet_iterator start, octet_iterator end, u32bit_iterator result)
Definition: checked.h:258
virtual DLLEXPORT void UpdateAllConnections()
#define LOG_INFO(x)
Definition: Define.h:90
RenderingStatistics * RenderTimer
Definition: Engine.h:304
DLLEXPORT void Info(const std::string &data) override
Definition: Logger.cpp:164
#define LOG_ERROR(x)
Definition: Define.h:92
Non-template class for working with all types of DataBlocks.
Definition: DataBlock.h:425
DLLEXPORT void OnFocusChange(bool focused)
Definition: Window.cpp:328
DLLEXPORT void InjectMouseButtonUp(const SDL_Event &event)
Definition: Window.cpp:1171
#define LOG_FATAL(x)
Definition: Define.h:94
DLLEXPORT void QueueTask(std::shared_ptr< QueuedTask > task)
Adds a task to the queue.
AppDef * Define
Definition: Engine.h:302
Random number generator based on Mersenne Twister.
Definition: Random.h:15
DLLEXPORT void CheckFileStatus()
Called by Engine to check are updated files available.
Manages loading the audio library and provides some helpers.
Definition: SoundDevice.h:15
DataStore * Mainstore
Definition: Engine.h:311
Allows object to register for events that can be fired from anywhere.
Definition: EventHandler.h:15
DLLEXPORT SecondDuration GetTimeSinceLastTick() const
Calculates how long has elapsed since the last tick.
Definition: Engine.cpp:1275
static std::atomic< int > WindowNameCounter
Used for automatic unique window names.
Definition: Engine.cpp:61
std::vector< std::unique_ptr< Editor::Importer > > QueuedImports
Queued importers from command line parsing.
Definition: Engine.h:386
DLLEXPORT void OnResize(int width, int height)
Definition: Window.cpp:312
constexpr auto THREAD_MAGIC
Definition: Engine.cpp:58
NetworkInterface * GetInterface()
Returns interface object. Type depends on AppType.
DLLEXPORT MasterServerInformation & GetMasterServerInfo()
Definition: AppDefine.h:97
IDFactory * IDDefaultInstance
Definition: Engine.h:332
NetworkHandler * _NetworkHandler
Definition: Engine.h:318
ScriptConsole * MainConsole
Definition: Engine.h:314
Class for indexing and searching game data directory.
Definition: FileSystem.h:65
DLLEXPORT void InjectKeyDown(const SDL_Event &event)
Definition: Window.cpp:1204
DLLEXPORT void ReInit(std::unique_ptr< StringDataIterator > &&iterator)
Changes the current iterator to the new iterator and goes to the beginning.
void _RunQueuedConsoleCommands()
Runs all commands in QueuedConsoleCommands.
Definition: Engine.cpp:1526
OutOfMemoryHandler * OutOMemory
Definition: Engine.h:317
DLLEXPORT void RenderFrame(float elapsed)
Definition: Engine.cpp:983
DLLEXPORT void SaveScreenShot()
Definition: Engine.cpp:1023
Handles ScriptModule creation and AngelScript code execution.
DLLEXPORT void ProcessInvokes()
Handles InvokeQueue.
Definition: Engine.cpp:1175
DLLEXPORT void Tick(float elapsed)
Called by Engine.
Definition: Window.cpp:294
DLLEXPORT void WaitForAllTasksToFinish()
Blocks until all queued tasks are finished.
DLLEXPORT void CollectGarbage()
Does a full garbage collection cycle.
std::chrono::duration< double, std::ratio< 1 > > PreciseSecondDuration
Definition: TimeIncludes.h:17
std::unique_ptr< RStrType > GetStringInQuotes(QUOTETYPE quotes, int specialflags=0)
Gets the next string in quotes.
static DLLEXPORT void ClearTimers()
bool _ReceiveConsoleInput(const std::string &command)
Console input comes through this.
Definition: Engine.cpp:1550
DLLEXPORT void OpenEditorWindow(Window *useexistingwindow=nullptr)
Opens an Editor::Editor window.
Definition: Engine.cpp:1133
Window * GraphicalEntity1
Definition: Engine.h:307
DLLEXPORT bool Init(AppDef *definition, NETWORKED_TYPE ntype, NetworkInterface *packethandler)
Definition: Engine.cpp:96
std::unique_ptr< ConsoleInput > _ConsoleInput
Definition: Engine.h:323
DLLEXPORT WindowDataDetails & GetWindowDetails()
Definition: AppDefine.h:93
The main class of the Leviathan Game Engine.
Definition: Engine.h:37
bool PreReleaseWaiting
Definition: Engine.h:358
std::vector< std::unique_ptr< std::string > > PassedCommands
Definition: Engine.h:380
Base class for all exceptions thrown by Leviathan.
Definition: Exceptions.h:10
#define LOG_WARNING(x)
Definition: Define.h:91
DLLEXPORT void InjectMouseMove(const SDL_Event &event)
Definition: Window.cpp:1099
DLLEXPORT void ReportClosedWindow(Window *windowentity)
Removes an closed window from the engine.
Definition: Engine.cpp:1108
DLLEXPORT bool Frame()
Definition: Graphics.cpp:537
DLLEXPORT void Save()
Definition: Logger.cpp:203
DLLEXPORT void MakeThreadsWorkWithOgre()
Makes the threads work with Ogre.
TimePoint LastTickTime
Time when last ticked, used to track elapsed time.
Definition: Engine.h:345
static thread_local int MainThreadMagic
Used to detect when accessed from main thread.
Definition: Engine.cpp:57
static bool IsCharacterQuote(CharType character)
std::lock_guard< std::recursive_mutex > RecursiveLock
Definition: ThreadSafe.h:19
DLLEXPORT void PreFirstTick()
Called by Application before the first Update call.
Definition: Engine.cpp:971
static DLLEXPORT int64_t GetTimeMs64()
DLLEXPORT bool Init()
DLLEXPORT bool Init(ScriptExecutor *MainScript)
Definition: Console.cpp:27
DLLEXPORT void SetAsMain()
Definition: Random.cpp:144
DLLEXPORT Engine(LeviathanApplication *owner)
Definition: Engine.cpp:63
virtual DLLEXPORT void Tick(float elapsed)
DLLEXPORT void Tick(float elapsed)
Definition: Engine.cpp:895
static DLLEXPORT GameWorldFactory * Get()
DLLEXPORT void NotifyQueuerThread()
Notifies the queuer thread to check task setting.
DLLEXPORT int RunConsoleCommand(std::string cmd)
Definition: Console.cpp:49
std::unique_ptr< RStrType > GetUntilNextCharacterOrAll(int charactertolookfor, int specialflags=0)
Gets characters until a character or all remaining characters.
DLLEXPORT NamedVars * GetValues()
Definition: AppDefine.cpp:40
DLLEXPORT int GetWindowOpenCount()
Definition: Engine.cpp:1033
DLLEXPORT bool IsValidWindow(Window *window) const
Definition: Engine.cpp:1054
DLLEXPORT void SetCloseIfNoRemoteConsole(bool state)
Sets the remote console to close the game if there are no connections.
DLLEXPORT void MarkAsClosing()
Thread safely marks the game to close sometime.
DLLEXPORT void Warning(const std::string &data) override
Definition: Logger.cpp:190
Iterator class for getting parts of a string.
Manages delayed execution of functions through use of QueuedTask and subclasses.
DLLEXPORT void FocusOrOpenEditor()
Focuses the first editor or opens an editor if none are open.
Definition: Engine.cpp:1152
#define LOG_WRITE(x)
Definition: Define.h:93
virtual DLLEXPORT void CloseDown()=0
Called when the program is closing.
DLLEXPORT void InputEnd()
Translates a client space coordinate to screen coordinate.
Definition: Window.cpp:1042
DLLEXPORT std::shared_ptr< Connection > OpenConnectionTo(const std::string &targetaddress)
Opens a new connection to the provided address.
Allows various resource loaders to get notified when the file on disk changes.
ThreadingManager * _ThreadingManager
Definition: Engine.h:319
NETWORKED_TYPE
Type of networked application.
Definition: CommonNetwork.h:22
DLLEXPORT void RunOnMainThread(const std::function< void()> &function)
Runs the function now if on the main thread otherwise calls Invoke.
Definition: Engine.cpp:1190
std::vector< std::unique_ptr< Editor::Editor > > OpenedEditors
Definition: Engine.h:325
#define SAFE_RELEASEDEL(x)
Definition: Define.h:141
void SkipCharacters(int chartoskip, int additionalflag=0, int specialflags=0)
Skips until chartoskip doesn't match the current character.
DLLEXPORT bool Init(const WorldNetworkSettings &network, Graphics *graphics)
Creates resources for the world to work.
Definition: GameWorld.cpp:95
DLLEXPORT void InjectKeyUp(const SDL_Event &event)
Definition: Window.cpp:1236
DLLEXPORT bool Init(LErrorReporter *errorreport)
Runs the indexing and sorting.
Definition: FileSystem.cpp:91
static DLLEXPORT TimePoint GetCurrentTimePoint()
DLLEXPORT bool Init(bool simulatesound=false)
Definition: SoundDevice.cpp:71
RemoteConsole * _RemoteConsole
Definition: Engine.h:320
DLLEXPORT Window * GetWindowFromSDLID(uint32_t sdlid)
Definition: Engine.cpp:806
static DLLEXPORT void Initialize()
#define LEVIATHAN_ASSERT(x, msg)
Definition: Define.h:100
SoundDevice * Sound
Definition: Engine.h:310
static std::string ToString(const T &val)
Definition: Convert.h:72
DLLEXPORT uint32_t GetSDLID() const
Definition: Window.cpp:906
virtual DLLEXPORT bool CheckInit()
Checks has Init worked.
DLLEXPORT void MessagePump()
Processes queued messages from SDL and CEF.
Definition: Engine.cpp:620
DLLEXPORT bool SetValue(const std::string &name, const VariableBlock &value1)
Definition: DataStore.cpp:164
DLLEXPORT void LinkObjects(std::shared_ptr< GameWorld > world)
This function also updates the camera aspect ratio.
Definition: Window.cpp:266
DLLEXPORT void SetTicksBehind(int value)
Definition: DataStore.cpp:411
std::vector< std::unique_ptr< std::string > > QueuedConsoleCommands
Stores console commands that came from the command line.
Definition: Engine.h:383
DLLEXPORT void SaveScreenShot(const std::string &filename)
Definition: Window.cpp:957
std::mutex NetworkHandlerLock
Mutex that is locked while NetworkHandler is used.
Definition: Engine.h:342
DLLEXPORT void CallEvent(Event *event)
ResourceRefreshHandler * _ResourceRefreshHandler
Definition: Engine.h:321
DLLEXPORT AppDef & SetWindowDetails(const WindowDataDetails &det)
Definition: AppDefine.h:75
DataBlock< int > IntBlock
Definition: DataBlock.h:382
DLLEXPORT void SetPersistance(unsigned int index, bool toset)
Definition: DataStore.cpp:135
static DLLEXPORT Logger * Get()
Definition: Logger.cpp:106
std::list< std::function< void()> > InvokeQueue
Definition: Engine.h:376
DLLEXPORT void SetDisallowRepeatingTasks(bool disallow)
Disallows repeating tasks to occur again.
std::unique_ptr< RStrType > GetNextNumber(DECIMALSEPARATORTYPE decimal, int specialflags=0)
Gets the next number.
DLLEXPORT void UnlinkAll()
Definition: Window.cpp:289
FileSystem * MainFileHandler
Definition: Engine.h:315
DLLEXPORT void InjectMouseButtonDown(const SDL_Event &event)
Definition: Window.cpp:1154
DLLEXPORT void Release()
Release resources.
Definition: GameWorld.cpp:122
DLLEXPORT bool CloseWindow(Window *window)
Closes a window.
Definition: Engine.cpp:1094
std::mutex GameWorldsLock
Mutex that is locked when changing the worlds.
Definition: Engine.h:339
DLLEXPORT Window * OpenNewWindow()
Opens a new window.
Definition: Engine.cpp:1069
static DLLEXPORT Engine * instance
Definition: Engine.h:388
#define DLLEXPORT
Definition: Include.h:84
RecursiveMutex InvokeLock
Definition: Engine.h:375
Random * MainRandom
Definition: Engine.h:316
virtual DLLEXPORT std::shared_ptr< GameWorld > CreateNewWorld(int worldtype, const std::shared_ptr< PhysicsMaterialManager > &physicsMaterials, int overrideid=-1)
Creates a new world that can be used.
DLLEXPORT void ReportStats(DataStore *dstore)
bool PreReleaseCompleted
Definition: Engine.h:372
DLLEXPORT void UnregisterGraphics()
Must be called if MakeThreadsWorkWithOgre has been called, BEFORE releasing graphics.
static DLLEXPORT Engine * GetEngine()
Definition: Engine.cpp:81
Data for EVENT_TYPE_ENGINE_TICK and all others that have only int data.
Definition: Event.h:90
DLLEXPORT void InjectCodePoint(const SDL_Event &event)
Injects text.
Definition: Window.cpp:1188
int TestCrash(int writenum)
Definition: Engine.cpp:1285
static DLLEXPORT Engine * Get()
Definition: Engine.cpp:86
DLLEXPORT bool CanRenderNow(int maxfps, int &TimeSinceLastFrame)
DLLEXPORT void SetTickTime(int newval)
Definition: DataStore.cpp:405
Base class for all leviathan programs.
Definition: Application.h:16
The access mask controls which registered functions and classes a script sees.
Definition: GameModule.h:12
DLLEXPORT float Update()
Runs an update cycle (tick and rendering if needed)
Definition: Engine.cpp:823
#define SAFE_DELETE(x)
Definition: Define.h:149
Class used to handle remote server commands and receiving messages.
Definition: RemoteConsole.h:45
constexpr auto DEFAULT_HEADLESS_MAX_UPDATES_PER_SECOND
Max "FPS" in headless mode.
Definition: Define.h:22
unsigned int uint32_t
Definition: core.h:40
int FrameLimit
Max FPS.
Definition: Engine.h:348
DLLEXPORT void ReleaseInputHandler()
Destroys the networked input handler and all input objects.
DLLEXPORT void ExecuteCommandLine()
Definition: Engine.cpp:1438
DLLEXPORT void Error(const std::string &data) override
Definition: Logger.cpp:177
Graphics * Graph
Definition: Engine.h:305
DLLEXPORT void OfferConnectionTo(std::shared_ptr< Connection > connectiontouse, const std::string &connectionname, int token)
Does everything needed to allow the client on the connection to connect to us.
Handles everything related to connections.
DLLEXPORT void AddVar(std::shared_ptr< NamedVariableList > values)
Definition: DataStore.cpp:208
bool PreReleaseDone
Set when PreRelease is called and Tick has happened.
Definition: Engine.h:354
DLLEXPORT bool PassCommandLine(int argcount, char *args[])
Definition: Engine.cpp:1294
DLLEXPORT std::shared_ptr< GameWorld > CreateWorld(Window *owningwindow, int worldtype, const std::shared_ptr< PhysicsMaterialManager > &physicsMaterials, const WorldNetworkSettings &networking, int overrideid=-1)
Creates a GameWorld for placing entities into.
Definition: Engine.cpp:1202
#define GUARD_LOCK()
Definition: ThreadSafe.h:111
std::vector< std::shared_ptr< GameWorld > > GameWorlds
List of current worlds.
Definition: Engine.h:336
DLLEXPORT void SetTickCount(int newval)
Definition: DataStore.cpp:399
static std::shared_ptr< GameWorld > CreateNewWorld(INBUILT_WORLD_TYPE worldtype, const std::shared_ptr< PhysicsMaterialManager > &physicsMaterials, int overrideid=-1)
Class that encapsulates common networking functionality that is required by all networked programs.
std::unique_lock< std::mutex > Lock
Definition: ThreadSafe.h:18
DLLEXPORT void DestroyWorld(const std::shared_ptr< GameWorld > &world)
Releases a GameWorld.
Definition: Engine.cpp:1234
virtual DLLEXPORT void PrintToLog() const noexcept
Definition: Exceptions.cpp:35
DLLEXPORT void AssertIfNotMainThread() const
Asserts if not called on the main thread.
Definition: Engine.h:111
std::chrono::duration< float, std::ratio< 1 > > SecondDuration
Definition: TimeIncludes.h:16
void SetAllowClose()
Called by Engine after command line has been processed.
std::unique_ptr< GameModuleLoader > _GameModuleLoader
Definition: Engine.h:324
bool IsClient
Set to true when initialized as a client.
Definition: Engine.h:369
DLLEXPORT void InjectMouseWheel(const SDL_Event &event)
Definition: Window.cpp:1121
static DLLEXPORT void DoCEFMessageLoopWork()
DLLEXPORT void Release(bool forced=false)
Definition: Engine.cpp:523
std::vector< Window * > AdditionalGraphicalEntities
Definition: Engine.h:308
virtual DLLEXPORT bool Init(const MasterServerInformation &info)
EventHandler * MainEvents
Definition: Engine.h:312
LeviathanApplication * Owner
Definition: Engine.h:333