Browse Source

move shutdown functions in EntryPoint

Simeon Manolov 1 year ago
parent
commit
20ccc92e6d
4 changed files with 145 additions and 189 deletions
  1. 0 159
      client/CMT.cpp
  2. 2 5
      client/CMT.h
  3. 0 1
      client/CMakeLists.txt
  4. 143 24
      clientapp/EntryPoint.cpp

+ 0 - 159
client/CMT.cpp

@@ -1,159 +0,0 @@
-/*
- * CMT.cpp, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-
-#include "StdInc.h"
-#include "CMT.h"
-
-#include "CGameInfo.h"
-#include "mainmenu/CMainMenu.h"
-#include "media/CMusicHandler.h"
-#include "media/CSoundHandler.h"
-#include "media/CVideoHandler.h"
-#include "gui/CursorHandler.h"
-#include "CPlayerInterface.h"
-#include "gui/CGuiHandler.h"
-#include "gui/WindowHandler.h"
-#include "CServerHandler.h"
-#include "windows/CMessage.h"
-#include "windows/InfoWindows.h"
-#include "render/IScreenHandler.h"
-#include "render/Graphics.h"
-
-#include "../lib/texts/CGeneralTextHandler.h"
-#include "../lib/VCMI_Lib.h"
-
-#include "../lib/logging/CBasicLogConfigurator.h"
-
-#include <SDL_main.h>
-#include <SDL.h>
-
-#ifdef VCMI_ANDROID
-#include "../lib/CAndroidVMHelper.h"
-#include <SDL_system.h>
-#endif
-
-#if __MINGW32__
-#undef main
-#endif
-extern std::atomic<bool> headlessQuit;
-extern std::optional<std::string> criticalInitializationError;
-extern CBasicLogConfigurator *logConfig;
-
-[[noreturn]] static void quitApplicationImmediately(int error_code)
-{
-	// Perform quick exit without executing static destructors and let OS cleanup anything that we did not
-	// We generally don't care about them and this leads to numerous issues, e.g.
-	// destruction of locked mutexes (fails an assertion), even in third-party libraries (as well as native libs on Android)
-	// Android - std::quick_exit is available only starting from API level 21
-	// Mingw, macOS and iOS - std::quick_exit is unavailable (at least in current version of CI)
-#if (defined(__ANDROID_API__) && __ANDROID_API__ < 21) || (defined(__MINGW32__)) || defined(VCMI_APPLE)
-	::exit(error_code);
-#else
-	std::quick_exit(error_code);
-#endif
-}
-
-[[noreturn]] void quitApplication()
-{
-	CSH->endNetwork();
-
-	if(!settings["session"]["headless"].Bool())
-	{
-		if(CSH->client)
-			CSH->endGameplay();
-
-		GH.windows().clear();
-	}
-
-	vstd::clear_pointer(CSH);
-
-	CMM.reset();
-
-	if(!settings["session"]["headless"].Bool())
-	{
-		// cleanup, mostly to remove false leaks from analyzer
-		if(CCS)
-		{
-			delete CCS->consoleh;
-			delete CCS->curh;
-			delete CCS->videoh;
-			delete CCS->musich;
-			delete CCS->soundh;
-
-			vstd::clear_pointer(CCS);
-		}
-		CMessage::dispose();
-
-		vstd::clear_pointer(graphics);
-	}
-
-	vstd::clear_pointer(VLC);
-
-	// sometimes leads to a hang. TODO: investigate
-	//vstd::clear_pointer(console);// should be removed after everything else since used by logging
-
-	if(!settings["session"]["headless"].Bool())
-		GH.screenHandler().close();
-
-	if(logConfig != nullptr)
-	{
-		logConfig->deconfigure();
-		delete logConfig;
-		logConfig = nullptr;
-	}
-
-	std::cout << "Ending...\n";
-	quitApplicationImmediately(0);
-}
-
-void handleQuit(bool ask)
-{
-	if(!ask)
-	{
-		if(settings["session"]["headless"].Bool())
-		{
-			headlessQuit = true;
-		}
-		else
-		{
-			quitApplication();
-		}
-
-		return;
-	}
-
-	// FIXME: avoids crash if player attempts to close game while opening is still playing
-	// use cursor handler as indicator that loading is not done yet
-	// proper solution would be to abort init thread (or wait for it to finish)
-	if (!CCS->curh)
-	{
-		quitApplicationImmediately(0);
-	}
-
-	if (LOCPLINT)
-		LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[69], quitApplication, nullptr);
-	else
-		CInfoWindow::showYesNoDialog(CGI->generaltexth->allTexts[69], {}, quitApplication, {}, PlayerColor(1));
-}
-
-void handleFatalError(const std::string & message, bool terminate)
-{
-	logGlobal->error("FATAL ERROR ENCOUNTERED, VCMI WILL NOW TERMINATE");
-	logGlobal->error("Reason: %s", message);
-
-	std::string messageToShow = "Fatal error! " + message;
-
-	SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error!", messageToShow.c_str(), nullptr);
-
-	if (terminate)
-		throw std::runtime_error(message);
-	else
-		quitApplicationImmediately(1);
-}

+ 2 - 5
client/CMT.h

@@ -20,9 +20,6 @@ extern SDL_Surface *screen;      // main screen surface
 extern SDL_Surface *screen2;     // and hlp surface (used to store not-active interfaces layer)
 extern SDL_Surface *screenBuf; // points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
 
+// defined in clientapp EntryPoint
 void handleQuit(bool ask = true);
-
-/// Notify user about encountered fatal error and terminate the game
-/// TODO: decide on better location for this method
-[[noreturn]] void handleFatalError(const std::string & message, bool terminate);
-[[noreturn]] void quitApplication();
+void handleFatalError(const std::string & message, bool terminate);

+ 0 - 1
client/CMakeLists.txt

@@ -177,7 +177,6 @@ set(vcmiclientcommon_SRCS
 
 	ArtifactsUIController.cpp
 	CGameInfo.cpp
-	CMT.cpp
 	CPlayerInterface.cpp
 	PlayerLocalState.cpp
 	CServerHandler.cpp

+ 143 - 24
clientapp/EntryPoint.cpp

@@ -9,33 +9,37 @@
  */
 
 // EntryPoint.cpp : Defines the entry point for the console application.
-#include "Global.h"
-#include "StdInc.h"
 
-#include "client/CGameInfo.h"
-#include "client/mainmenu/CMainMenu.h"
-#include "media/CEmptyVideoPlayer.h"
-#include "media/CMusicHandler.h"
-#include "media/CSoundHandler.h"
-#include "media/CVideoHandler.h"
-#include "client/gui/CursorHandler.h"
-#include "client/eventsSDL/InputHandler.h"
-#include "client/gui/CGuiHandler.h"
-#include "client/CServerHandler.h"
-#include "client/ClientCommandManager.h"
-#include "client/windows/CMessage.h"
-#include "client/render/IRenderHandler.h"
-#include "client/render/IScreenHandler.h"
-#include "client/render/Graphics.h"
-#include "client/CMT.h"
+#include "StdInc.h"
+#include "../Global.h"
+
+#include "../client/CGameInfo.h"
+#include "../client/ClientCommandManager.h"
+#include "../client/CMT.h"
+#include "../client/CPlayerInterface.h"
+#include "../client/CServerHandler.h"
+#include "../client/eventsSDL/InputHandler.h"
+#include "../client/gui/CGuiHandler.h"
+#include "../client/gui/CursorHandler.h"
+#include "../client/gui/WindowHandler.h"
+#include "../client/mainmenu/CMainMenu.h"
+#include "../client/media/CEmptyVideoPlayer.h"
+#include "../client/media/CMusicHandler.h"
+#include "../client/media/CSoundHandler.h"
+#include "../client/media/CVideoHandler.h"
+#include "../client/render/Graphics.h"
+#include "../client/render/IRenderHandler.h"
+#include "../client/render/IScreenHandler.h"
+#include "../client/windows/CMessage.h"
+#include "../client/windows/InfoWindows.h"
 
 #include "../lib/CThreadHelper.h"
 #include "../lib/ExceptionsCommon.h"
-#include "../lib/VCMIDirs.h"
-#include "../lib/VCMI_Lib.h"
 #include "../lib/filesystem/Filesystem.h"
-
 #include "../lib/logging/CBasicLogConfigurator.h"
+#include "../lib/texts/CGeneralTextHandler.h"
+#include "../lib/VCMI_Lib.h"
+#include "../lib/VCMIDirs.h"
 
 #include <boost/program_options.hpp>
 #include <vstd/StringUtils.h>
@@ -55,16 +59,17 @@
 namespace po = boost::program_options;
 namespace po_style = boost::program_options::command_line_style;
 
-std::atomic<bool> headlessQuit = false;
-std::optional<std::string> criticalInitializationError;
+static std::atomic<bool> headlessQuit = false;
+static std::optional<std::string> criticalInitializationError;
 
 #ifndef VCMI_IOS
 void processCommand(const std::string &message);
 #endif
 void playIntro();
+[[noreturn]] static void quitApplication();
 static void mainLoop();
 
-CBasicLogConfigurator *logConfig;
+static CBasicLogConfigurator *logConfig;
 
 void init()
 {
@@ -422,3 +427,117 @@ static void mainLoop()
 		GH.renderFrame();
 	}
 }
+
+[[noreturn]] static void quitApplicationImmediately(int error_code)
+{
+	// Perform quick exit without executing static destructors and let OS cleanup anything that we did not
+	// We generally don't care about them and this leads to numerous issues, e.g.
+	// destruction of locked mutexes (fails an assertion), even in third-party libraries (as well as native libs on Android)
+	// Android - std::quick_exit is available only starting from API level 21
+	// Mingw, macOS and iOS - std::quick_exit is unavailable (at least in current version of CI)
+#if (defined(__ANDROID_API__) && __ANDROID_API__ < 21) || (defined(__MINGW32__)) || defined(VCMI_APPLE)
+	::exit(error_code);
+#else
+	std::quick_exit(error_code);
+#endif
+}
+
+[[noreturn]] static void quitApplication()
+{
+	CSH->endNetwork();
+
+	if(!settings["session"]["headless"].Bool())
+	{
+		if(CSH->client)
+			CSH->endGameplay();
+
+		GH.windows().clear();
+	}
+
+	vstd::clear_pointer(CSH);
+
+	CMM.reset();
+
+	if(!settings["session"]["headless"].Bool())
+	{
+		// cleanup, mostly to remove false leaks from analyzer
+		if(CCS)
+		{
+			delete CCS->consoleh;
+			delete CCS->curh;
+			delete CCS->videoh;
+			delete CCS->musich;
+			delete CCS->soundh;
+
+			vstd::clear_pointer(CCS);
+		}
+		CMessage::dispose();
+
+		vstd::clear_pointer(graphics);
+	}
+
+	vstd::clear_pointer(VLC);
+
+	// sometimes leads to a hang. TODO: investigate
+	//vstd::clear_pointer(console);// should be removed after everything else since used by logging
+
+	if(!settings["session"]["headless"].Bool())
+		GH.screenHandler().close();
+
+	if(logConfig != nullptr)
+	{
+		logConfig->deconfigure();
+		delete logConfig;
+		logConfig = nullptr;
+	}
+
+	std::cout << "Ending...\n";
+	quitApplicationImmediately(0);
+}
+
+void handleQuit(bool ask)
+{
+	if(!ask)
+	{
+		if(settings["session"]["headless"].Bool())
+		{
+			headlessQuit = true;
+		}
+		else
+		{
+			quitApplication();
+		}
+
+		return;
+	}
+
+	// FIXME: avoids crash if player attempts to close game while opening is still playing
+	// use cursor handler as indicator that loading is not done yet
+	// proper solution would be to abort init thread (or wait for it to finish)
+	if (!CCS->curh)
+	{
+		quitApplicationImmediately(0);
+	}
+
+	if (LOCPLINT)
+		LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[69], quitApplication, nullptr);
+	else
+		CInfoWindow::showYesNoDialog(CGI->generaltexth->allTexts[69], {}, quitApplication, {}, PlayerColor(1));
+}
+
+/// Notify user about encountered fatal error and terminate the game
+/// TODO: decide on better location for this method
+void handleFatalError(const std::string & message, bool terminate)
+{
+	logGlobal->error("FATAL ERROR ENCOUNTERED, VCMI WILL NOW TERMINATE");
+	logGlobal->error("Reason: %s", message);
+
+	std::string messageToShow = "Fatal error! " + message;
+
+	SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error!", messageToShow.c_str(), nullptr);
+
+	if (terminate)
+		throw std::runtime_error(message);
+	else
+		quitApplicationImmediately(1);
+}