Leviathan  0.8.0.0
Leviathan game engine
Application.cpp
Go to the documentation of this file.
1 // ------------------------------------ //
2 #include "Application.h"
3 
4 #include "FileSystem.h"
6 #include "TimeIncludes.h"
7 
8 using namespace Leviathan;
9 // ------------------------------------ //
11 {
12  Curapp = this;
13 }
14 
17  ExternalEngineInstance(true), _Engine(engine)
18 {
19  LEVIATHAN_ASSERT(_Engine, "no engine pointer given");
20  Curapp = this;
21 }
22 
24 {
25  // Release should have been called when exiting the main loop
28  _Engine = nullptr;
29  Curapp = nullptr;
30 }
31 
33 {
34  return Curapp;
35 }
36 
38 // ------------------------------------ //
40 {
41  GUARD_LOCK();
42 
43  // Store configuration //
44  ApplicationConfiguration = configuration;
45 
46  // Init engine //
47  if(!_Engine->Init(
49  return false;
50 
51  _InternalInit();
52  return true;
53 }
54 
56 {
57  {
58  GUARD_LOCK();
59  // set as quitting //
60  Quit = true;
61 
62  // Nothing else to do if no engine //
63  if(!_Engine)
64  return;
65 
66  // Shutdown the packet handler
67  // PreRelease should have been done at this point and the NetworkHandler
68  // should have been released so this can no longer be in use
70  }
71 
72  // This avoids deadlocking //
73  _Engine->Release();
74 
75  {
76  GUARD_LOCK();
77  // Delete the already released engine //
78  delete _Engine;
79  _Engine = NULL;
80  }
81 }
82 
84 {
85  GUARD_LOCK();
86  ShouldQuit = true;
87 
88  // Tell Engine to expect a Release soon //
90 }
91 // ------------------------------------ //
93 {
94  GUARD_LOCK();
95  ShouldQuit = true;
96  Quit = true;
97 
98  if(_Engine) {
99  // The prelease does some which requires a tick //
100  _Engine->PreRelease();
101  _Engine->Update();
102  _Engine->Release(true);
103  }
104 
106 }
107 // ------------------------------------ //
108 DLLEXPORT bool LeviathanApplication::PassCommandLine(int argcount, char* args[])
109 {
110  return _Engine->PassCommandLine(argcount, args);
111 }
112 
113 
114 // ------------------------------------ //
116 {
117  return _Engine->Update();
118 }
119 // ------------------------------------ //
121 {
123  PreFirstTick();
124 
125  // For reporting wait failures //
126  int FailCount = 0;
127 
128  // Run until engine prerelease is done.
129  // We need to have done a proper run after calling StartRelease
130  while(!_Engine->HasPreReleaseBeenDone()) {
131  // Store this //
132  bool canprocess = _Engine->GetWindowOpenCount() != 0;
133 
134  _Engine->MessagePump();
135 
136  // Set as quitting //
137  if((!canprocess || QuitSometime) && !ShouldQuit) {
138  Logger::Get()->Info("Application: starting real close");
139  StartRelease();
140  }
141 
142  // Engine tick and render
143  const float waitTime = RunSingleUpdate();
144 
145  if(ShouldQuit || Quit) {
146  continue;
147  }
148 
149  if(waitTime > 0) {
150 
151  if(waitTime >= 0.002f || PreferSleepOverLoopAccuracy) {
152  try {
153  std::this_thread::sleep_for(SecondDuration(waitTime));
154  } catch(...) {
155  FailCount++;
156  }
157  } else {
158  // Busy wait the duration
159  const auto start = Time::GetCurrentTimePoint();
160 
161  while(std::chrono::duration_cast<SecondDuration>(
162  Time::GetCurrentTimePoint() - start)
163  .count() < waitTime) {
164  }
165  }
166  }
167  }
168 
169  // Report problems //
170  if(FailCount) {
171  if(Logger::Get())
172  Logger::Get()->Error(
173  "Application main loop sleep fails: " + std::to_string(FailCount));
174  }
175 
176  // always release before quitting to avoid tons of memory leaks //
177  Release();
178 
179  return 0;
180 }
181 // ------------------------------------ //
183 {
184  _Engine->ClearTimers();
185 }
186 // ------------------ Default callbacks that do nothing ------------------ //
188 {
189  return true;
190 }
191 
192 DLLEXPORT void LeviathanApplication::Tick(float elapsed) {}
193 
195 
197 
199 
201 
202 DLLEXPORT std::shared_ptr<GameWorld> LeviathanApplication::GetGameWorld(int id)
203 {
204  return nullptr;
205 }
206 
207 
209  GameConfiguration* configobj)
210 {}
211 
213  KeyConfiguration* keyconfigobj)
214 {}
215 // ------------------------------------ //
217 {
218  QuitSometime = true;
219 }
220 // ------------------------------------ //
222  const std::string& processname, const std::string& commandline)
223 {
224 
225 #ifdef _WIN32
226  // Create needed info //
227  STARTUPINFOA processstart;
228  PROCESS_INFORMATION startedinfo;
229 
230  ZeroMemory(&processstart, sizeof(STARTUPINFOA));
231  ZeroMemory(&startedinfo, sizeof(PROCESS_INFORMATION));
232 
233  processstart.cb = sizeof(STARTUPINFOA);
234  // processstart.dwFlags = STARTF_FORCEOFFFEEDBACK;
235  // processstart.wShowWindow = SW_SHOWMINIMIZED;
236 
237  std::string finalstart = "\"" + processname + "\" " + commandline;
238 
239  // Use windows process creation //
240  if(!CreateProcessA(NULL, const_cast<char*>(finalstart.c_str()), NULL, NULL, FALSE, 0, NULL,
241  NULL, &processstart, &startedinfo)) {
242  // Failed to start the process
243  Logger::Get()->Error("Failed to start the server process, error code: " +
244  Convert::ToString(GetLastError()));
245  return;
246  }
247 
248  // Close our handles //
249  CloseHandle(startedinfo.hThread);
250  DEBUG_BREAK;
251  // ServerProcessHandle = startedinfo.hProcess;
252 
253 
254 #else
255  // Popen should work //
256 
257  // Actually fork might be simpler //
258  if(fork() == 0) {
259  // We are now in the child process //
260 
261  execl(processname.c_str(), commandline.c_str(), (char*)NULL);
262  }
263 
264 
265 #endif // _WIN32
266 }
267 // ------------------------------------ //
269  const char* str, std::vector<char*>& argcharstrings, bool addprogramname /*= true*/)
270 {
271  StringIterator itr(std::make_unique<UTF8PointerDataIterator>(str, str + std::strlen(str)));
272 
273  std::vector<std::string> args;
274 
275  if(addprogramname) {
276  // TODO: actually detect this somehow
277  args.push_back("LeviathanApplication");
278  }
279 
280  while(!itr.IsOutOfBounds()) {
281  auto current =
283 
284  if(current && current->size() > 0) {
285  if(current->at(0) == '\'' || current->at(0) == '\"') {
286  current = StringIterator(current.get())
287  .GetStringInQuotes<std::string>(QUOTETYPE_BOTH);
288  }
289 
290  args.push_back(*current);
291  }
292  }
293 
294  argcharstrings.resize(args.size());
295  for(size_t i = 0; i < args.size(); ++i) {
296  argcharstrings[i] = const_cast<char*>(args[i].c_str());
297  }
298  argcharstrings.push_back(nullptr);
299 
300  return args;
301 }
DLLEXPORT void PreRelease()
Sets objects ready to be released.
Definition: Engine.cpp:460
DLLEXPORT void ClearTimers()
Clears physical timers.
Definition: Engine.cpp:1256
virtual DLLEXPORT void EnginePreShutdown()
DLLEXPORT void Info(const std::string &data) override
Definition: Logger.cpp:164
Holds key configuration for an application.
static DLLEXPORT void DummyGameConfigurationVariables(GameConfiguration *configobj)
bool IsOutOfBounds()
Returns true when the read position is valid.
static LeviathanApplication * Curapp
Definition: Application.h:138
virtual NetworkInterface * _GetApplicationPacketHandler()=0
Called in Initialize to get the derived packet handler type.
DLLEXPORT bool HasPreReleaseBeenDone() const
Checks if PreRelease is done and Release can be called.
Definition: Engine.h:60
virtual DLLEXPORT int RunMessageLoop()
virtual DLLEXPORT NETWORKED_TYPE GetProgramNetType() const =0
virtual DLLEXPORT void _InternalInit()
DLLEXPORT bool Init(AppDef *definition, NETWORKED_TYPE ntype, NetworkInterface *packethandler)
Definition: Engine.cpp:96
The main class of the Leviathan Game Engine.
Definition: Engine.h:37
virtual DLLEXPORT std::shared_ptr< GameWorld > GetGameWorld(int id)
Used to query a world for specific id.
DLLEXPORT void ForceRelease()
Used to immediately terminate the program.
Definition: Application.cpp:92
static DLLEXPORT std::vector< std::string > CommandLineStringSplitter(const char *str, std::vector< char * > &argcharstrings, bool addprogramname=true)
Splits a single string command line into arguments.
virtual DLLEXPORT void PreFirstTick()
virtual DLLEXPORT bool Initialize(AppDef *configuration)
Definition: Application.cpp:39
DLLEXPORT void PreFirstTick()
Called by Application before the first Update call.
Definition: Engine.cpp:971
virtual DLLEXPORT ~LeviathanApplication()
Definition: Application.cpp:23
virtual DLLEXPORT void Tick(float elapsed)
DLLEXPORT int GetWindowOpenCount()
Definition: Engine.cpp:1033
DLLEXPORT void MarkAsClosing()
Thread safely marks the game to close sometime.
virtual DLLEXPORT bool PassCommandLine(int argcount, char *args[])
Iterator class for getting parts of a string.
virtual DLLEXPORT void Release()
Performs the final steps in the release process.
Definition: Application.cpp:55
virtual DLLEXPORT bool InitLoadCustomScriptTypes(asIScriptEngine *engine)
DLLEXPORT void ClearTimers()
Resets all time sensitive timers.
static DLLEXPORT TimePoint GetCurrentTimePoint()
#define LEVIATHAN_ASSERT(x, msg)
Definition: Define.h:104
static std::string ToString(const T &val)
Definition: Convert.h:72
static DLLEXPORT void DummyGameKeyConfigVariables(KeyConfiguration *keyconfigobj)
DLLEXPORT void MessagePump()
Processes queued messages from SDL and CEF.
Definition: Engine.cpp:620
virtual DLLEXPORT void StartRelease()
Safely releases the Application //.
Definition: Application.cpp:83
virtual DLLEXPORT float RunSingleUpdate()
Runs a single engine update cycle (tick + render)
static DLLEXPORT void StartServerProcess(const std::string &processname, const std::string &commandline)
static DLLEXPORT Logger * Get()
Definition: Logger.cpp:106
static DLLEXPORT LeviathanApplication * Get()
Definition: Application.cpp:32
virtual void _ShutdownApplicationPacketHandler()=0
#define DLLEXPORT
Definition: Include.h:84
Base class for all leviathan programs.
Definition: Application.h:16
virtual DLLEXPORT void CustomizeEnginePostLoad()
The access mask controls which registered functions and classes a script sees.
Definition: GameModule.h:12
DLLEXPORT float Update()
Runs an update cycle (tick and rendering if needed)
Definition: Engine.cpp:823
#define SAFE_DELETE(x)
Definition: Define.h:153
DLLEXPORT void Error(const std::string &data) override
Definition: Logger.cpp:177
DLLEXPORT bool PassCommandLine(int argcount, char *args[])
Definition: Engine.cpp:1294
#define GUARD_LOCK()
Definition: ThreadSafe.h:111
bool QuitSometime
This can be quickly set anywhere to quit sometime in the future.
Definition: Application.h:125
std::chrono::duration< float, std::ratio< 1 > > SecondDuration
Definition: TimeIncludes.h:16
std::unique_ptr< RStrType > GetNextCharacterSequence(int stopcaseflags, int specialflags=0)
Gets the next sequence of characters according to stopcaseflags.
DLLEXPORT void Release(bool forced=false)
Definition: Engine.cpp:523