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