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