فهرست منبع

Moved shutdown request dialog handling to GameInstance

Ivan Savenko 7 ماه پیش
والد
کامیت
9732d39c70

+ 1 - 1
client/CMT.h

@@ -16,4 +16,4 @@ extern SDL_Renderer * mainRenderer;
 /// Defined in clientapp EntryPoint
 /// TODO: decide on better location for this method
 [[noreturn]] void handleFatalError(const std::string & message, bool terminate);
-void handleQuit(bool ask = true);
+[[noreturn]] void quitApplication();

+ 3 - 0
client/GameEngineUser.h

@@ -20,6 +20,9 @@ public:
 	/// Called on every game tick for game to update its state
 	virtual void onUpdate() = 0;
 
+	/// Called when app shutdown has been requested in any way - exit button, Alt-F4, etc
+	virtual void onShutdownRequested(bool askForConfirmation) = 0;
+
 	/// Returns true if all input events should be captured and ignored
 	virtual bool capturedAllEvents() = 0;
 };

+ 17 - 0
client/GameInstance.cpp

@@ -11,12 +11,16 @@
 #include "GameInstance.h"
 
 #include "CPlayerInterface.h"
+#include "CMT.h"
 #include "CServerHandler.h"
 #include "mapView/mapHandler.h"
 #include "globalLobby/GlobalLobbyClient.h"
 #include "mainmenu/CMainMenu.h"
+#include "windows/InfoWindows.h"
 
 #include "../lib/CConfigHandler.h"
+#include "../lib/GameLibrary.h"
+#include "../lib/texts/CGeneralTextHandler.h"
 
 std::unique_ptr<GameInstance> GAME = nullptr;
 
@@ -93,3 +97,16 @@ bool GameInstance::capturedAllEvents()
 	else
 		return false;
 }
+
+void GameInstance::onShutdownRequested(bool ask)
+{
+	if(!ask)
+		quitApplication();
+	else
+	{
+		if (interface())
+			interface()->showYesNoDialog(LIBRARY->generaltexth->allTexts[69], quitApplication, nullptr);
+		else
+			CInfoWindow::showYesNoDialog(LIBRARY->generaltexth->allTexts[69], {}, quitApplication, {}, PlayerColor(1));
+	}
+}

+ 1 - 0
client/GameInstance.h

@@ -45,6 +45,7 @@ public:
 	void onGlobalLobbyInterfaceActivated() final;
 	void onUpdate() final;
 	bool capturedAllEvents() final;
+	void onShutdownRequested(bool askForConfirmation) final;
 };
 
 extern std::unique_ptr<GameInstance> GAME;

+ 1 - 1
client/NetPacksClient.cpp

@@ -418,7 +418,7 @@ void ApplyClientNetPackVisitor::visitPlayerEndsGame(PlayerEndsGame & pack)
 	{
 		logAi->info("Red player %s. Ending game.", pack.victoryLossCheckResult.victory() ? "won" : "lost");
 
-		handleQuit(settings["session"]["spectate"].Bool()); // if spectator is active ask to close client or not
+		GAME->onShutdownRequested(settings["session"]["spectate"].Bool()); // if spectator is active ask to close client or not
 	}
 }
 

+ 2 - 8
client/adventureMap/AdventureMapShortcuts.cpp

@@ -354,14 +354,8 @@ void AdventureMapShortcuts::quitGame()
 {
 	GAME->interface()->showYesNoDialog(
 		LIBRARY->generaltexth->allTexts[578],
-		[]()
-		{
-			ENGINE->dispatchMainThread( []()
-			{
-				handleQuit(false);
-			});
-		},
-		0
+		[](){ GAME->onShutdownRequested(false);},
+		nullptr
 		);
 }
 

+ 5 - 4
client/eventsSDL/InputHandler.cpp

@@ -19,6 +19,7 @@
 #include "InputSourceGameController.h"
 
 #include "../GameEngine.h"
+#include "../GameEngineUser.h"
 #include "../gui/CursorHandler.h"
 #include "../gui/EventDispatcher.h"
 #include "../gui/MouseButton.h"
@@ -194,9 +195,9 @@ void InputHandler::preprocessEvent(const SDL_Event & ev)
 	{
 		std::scoped_lock interfaceLock(ENGINE->interfaceMutex);
 #ifdef VCMI_ANDROID
-		handleQuit(false);
+		ENGINE->user().onShutdownRequested(false);
 #else
-		handleQuit(true);
+		ENGINE->user().onShutdownRequested(true);
 #endif
 		return;
 	}
@@ -206,14 +207,14 @@ void InputHandler::preprocessEvent(const SDL_Event & ev)
 		{
 			// FIXME: dead code? Looks like intercepted by OS/SDL and delivered as SDL_Quit instead?
 			std::scoped_lock interfaceLock(ENGINE->interfaceMutex);
-			handleQuit(true);
+			ENGINE->user().onShutdownRequested(true);
 			return;
 		}
 
 		if(ev.key.keysym.scancode == SDL_SCANCODE_AC_BACK && !settings["input"]["handleBackRightMouseButton"].Bool())
 		{
 			std::scoped_lock interfaceLock(ENGINE->interfaceMutex);
-			handleQuit(true);
+			ENGINE->user().onShutdownRequested(true);
 			return;
 		}
 	}

+ 1 - 9
client/mainmenu/CMainMenu.cpp

@@ -64,14 +64,6 @@
 
 ISelectionScreenInfo * SEL = nullptr;
 
-static void do_quit()
-{
-	ENGINE->dispatchMainThread([]()
-	{
-		handleQuit(false);
-	});
-}
-
 CMenuScreen::CMenuScreen(const JsonNode & configNode)
 	: CWindowObject(BORDERED), config(configNode)
 {
@@ -210,7 +202,7 @@ static std::function<void()> genCommand(CMenuScreen * menu, std::vector<std::str
 			break;
 			case 4: //exit
 			{
-				return []() { CInfoWindow::showYesNoDialog(LIBRARY->generaltexth->allTexts[69], std::vector<std::shared_ptr<CComponent>>(), do_quit, 0, PlayerColor(1)); };
+				return []() { CInfoWindow::showYesNoDialog(LIBRARY->generaltexth->allTexts[69], std::vector<std::shared_ptr<CComponent>>(), [](){GAME->onShutdownRequested(false);}, 0, PlayerColor(1)); };
 			}
 			break;
 			case 5: //highscores

+ 2 - 5
client/windows/settings/SettingsMainWindow.cpp

@@ -125,12 +125,9 @@ void SettingsMainWindow::quitGameButtonCallback()
 		[this]()
 		{
 			close();
-			ENGINE->dispatchMainThread( []()
-			{
-				handleQuit(false);
-			});
+			ENGINE->user().onShutdownRequested(false);
 		},
-		0
+		nullptr
 	);
 }
 

+ 11 - 54
clientapp/EntryPoint.cpp

@@ -17,24 +17,19 @@
 #include "../client/CMT.h"
 #include "../client/CPlayerInterface.h"
 #include "../client/CServerHandler.h"
-#include "../client/eventsSDL/InputHandler.h"
 #include "../client/GameEngine.h"
 #include "../client/GameInstance.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/lobby/CBonusSelection.h"
 #include "../client/windows/CMessage.h"
 #include "../client/windows/InfoWindows.h"
 
 #include "../lib/CConsoleHandler.h"
+#include "../lib/CConfigHandler.h"
 #include "../lib/CThreadHelper.h"
 #include "../lib/ExceptionsCommon.h"
 #include "../lib/filesystem/Filesystem.h"
@@ -42,7 +37,6 @@
 #include "../lib/modding/IdentifierStorage.h"
 #include "../lib/modding/CModHandler.h"
 #include "../lib/modding/ModDescription.h"
-#include "../lib/texts/CGeneralTextHandler.h"
 #include "../lib/texts/MetaString.h"
 #include "../lib/GameLibrary.h"
 #include "../lib/VCMIDirs.h"
@@ -68,9 +62,7 @@ namespace po_style = boost::program_options::command_line_style;
 static std::atomic<bool> headlessQuit = false;
 static std::optional<std::string> criticalInitializationError;
 
-[[noreturn]] static void quitApplication();
-
-static CBasicLogConfigurator *logConfig;
+[[noreturn]] extern void quitApplication();
 
 static void init()
 {
@@ -402,22 +394,9 @@ int main(int argc, char * argv[])
 
 		quitApplication();
 	}
-
-[[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()
+[[noreturn]] void quitApplication()
 {
 	GAME->server().endNetwork();
 
@@ -446,39 +425,17 @@ int main(int argc, char * argv[])
 	if(!settings["session"]["headless"].Bool())
 		ENGINE->screenHandler().close();
 
-	if(logConfig != nullptr)
-	{
-		logConfig->deconfigure();
-		delete logConfig;
-		logConfig = nullptr;
-	}
+	//if(logConfig != nullptr)
+	//{
+	//	logConfig->deconfigure();
+	//	delete logConfig;
+	//	logConfig = nullptr;
+	//}
 
 	//ENGINE.reset();
 
 	std::cout << "Ending...\n";
-	quitApplicationImmediately(0);
-}
-
-void handleQuit(bool ask)
-{
-	if(!ask)
-	{
-		if(settings["session"]["headless"].Bool())
-		{
-			headlessQuit = true;
-		}
-		else
-		{
-			quitApplication();
-		}
-
-		return;
-	}
-
-	if (GAME->interface())
-		GAME->interface()->showYesNoDialog(LIBRARY->generaltexth->allTexts[69], quitApplication, nullptr);
-	else
-		CInfoWindow::showYesNoDialog(LIBRARY->generaltexth->allTexts[69], {}, quitApplication, {}, PlayerColor(1));
+	::exit(0);
 }
 
 /// Notify user about encountered fatal error and terminate the game
@@ -495,5 +452,5 @@ void handleFatalError(const std::string & message, bool terminate)
 	if (terminate)
 		throw std::runtime_error(message);
 	else
-		quitApplicationImmediately(1);
+		::exit(1);
 }