mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Split vcmiclient in two
Similar to vcmiserver (app) and vcmiservercommon (lib), now there is vcmiclient (app) and vcmiclientcommon (lib).
This commit is contained in:
		| @@ -677,6 +677,7 @@ endif() | ||||
|  | ||||
| if (ENABLE_CLIENT) | ||||
| 	add_subdirectory(client) | ||||
| 	add_subdirectory(clientapp) | ||||
| endif() | ||||
|  | ||||
| if(ENABLE_SERVER) | ||||
|   | ||||
							
								
								
									
										390
									
								
								client/CMT.cpp
									
									
									
									
									
								
							
							
						
						
									
										390
									
								
								client/CMT.cpp
									
									
									
									
									
								
							| @@ -8,42 +8,29 @@ | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| // CMT.cpp : Defines the entry point for the console application. | ||||
| #include "StdInc.h" | ||||
| #include "CMT.h" | ||||
|  | ||||
| #include "CGameInfo.h" | ||||
| #include "mainmenu/CMainMenu.h" | ||||
| #include "media/CEmptyVideoPlayer.h" | ||||
| #include "media/CMusicHandler.h" | ||||
| #include "media/CSoundHandler.h" | ||||
| #include "media/CVideoHandler.h" | ||||
| #include "gui/CursorHandler.h" | ||||
| #include "eventsSDL/InputHandler.h" | ||||
| #include "CPlayerInterface.h" | ||||
| #include "gui/CGuiHandler.h" | ||||
| #include "gui/WindowHandler.h" | ||||
| #include "CServerHandler.h" | ||||
| #include "ClientCommandManager.h" | ||||
| #include "windows/CMessage.h" | ||||
| #include "windows/InfoWindows.h" | ||||
| #include "render/IScreenHandler.h" | ||||
| #include "render/IRenderHandler.h" | ||||
| #include "render/Graphics.h" | ||||
|  | ||||
| #include "../lib/CConfigHandler.h" | ||||
| #include "../lib/texts/CGeneralTextHandler.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 <boost/program_options.hpp> | ||||
| #include <vstd/StringUtils.h> | ||||
|  | ||||
| #include <SDL_main.h> | ||||
| #include <SDL.h> | ||||
|  | ||||
| @@ -55,378 +42,9 @@ | ||||
| #if __MINGW32__ | ||||
| #undef main | ||||
| #endif | ||||
|  | ||||
| namespace po = boost::program_options; | ||||
| namespace po_style = boost::program_options::command_line_style; | ||||
|  | ||||
| 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(); | ||||
|  | ||||
| static CBasicLogConfigurator *logConfig; | ||||
|  | ||||
| void init() | ||||
| { | ||||
| 	CStopWatch tmh; | ||||
| 	try | ||||
| 	{ | ||||
| 		loadDLLClasses(); | ||||
| 		CGI->setFromLib(); | ||||
| 	} | ||||
| 	catch (const DataLoadingException & e) | ||||
| 	{ | ||||
| 		criticalInitializationError = e.what(); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	logGlobal->info("Initializing VCMI_Lib: %d ms", tmh.getDiff()); | ||||
|  | ||||
| 	// Debug code to load all maps on start | ||||
| 	//ClientCommandManager commandController; | ||||
| 	//commandController.processCommand("convert txt", false); | ||||
| } | ||||
|  | ||||
| static void prog_version() | ||||
| { | ||||
| 	printf("%s\n", GameConstants::VCMI_VERSION.c_str()); | ||||
| 	std::cout << VCMIDirs::get().genHelpString(); | ||||
| } | ||||
|  | ||||
| static void prog_help(const po::options_description &opts) | ||||
| { | ||||
| 	auto time = std::time(nullptr); | ||||
| 	printf("%s - A Heroes of Might and Magic 3 clone\n", GameConstants::VCMI_VERSION.c_str()); | ||||
| 	printf("Copyright (C) 2007-%d VCMI dev team - see AUTHORS file\n", std::localtime(&time)->tm_year + 1900); | ||||
| 	printf("This is free software; see the source for copying conditions. There is NO\n"); | ||||
| 	printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); | ||||
| 	printf("\n"); | ||||
| 	std::cout << opts; | ||||
| } | ||||
|  | ||||
| #if defined(VCMI_WINDOWS) && !defined(__GNUC__) && defined(VCMI_WITH_DEBUG_CONSOLE) | ||||
| int wmain(int argc, wchar_t* argv[]) | ||||
| #elif defined(VCMI_MOBILE) | ||||
| int SDL_main(int argc, char *argv[]) | ||||
| #else | ||||
| int main(int argc, char * argv[]) | ||||
| #endif | ||||
| { | ||||
| #ifdef VCMI_ANDROID | ||||
| 	CAndroidVMHelper::initClassloader(SDL_AndroidGetJNIEnv()); | ||||
| 	// boost will crash without this | ||||
| 	setenv("LANG", "C", 1); | ||||
| #endif | ||||
|  | ||||
| #if !defined(VCMI_MOBILE) | ||||
| 	// Correct working dir executable folder (not bundle folder) so we can use executable relative paths | ||||
| 	boost::filesystem::current_path(boost::filesystem::system_complete(argv[0]).parent_path()); | ||||
| #endif | ||||
| 	std::cout << "Starting... " << std::endl; | ||||
| 	po::options_description opts("Allowed options"); | ||||
| 	po::variables_map vm; | ||||
|  | ||||
| 	opts.add_options() | ||||
| 		("help,h", "display help and exit") | ||||
| 		("version,v", "display version information and exit") | ||||
| 		("testmap", po::value<std::string>(), "") | ||||
| 		("testsave", po::value<std::string>(), "") | ||||
| 		("spectate,s", "enable spectator interface for AI-only games") | ||||
| 		("spectate-ignore-hero", "wont follow heroes on adventure map") | ||||
| 		("spectate-hero-speed", po::value<int>(), "hero movement speed on adventure map") | ||||
| 		("spectate-battle-speed", po::value<int>(), "battle animation speed for spectator") | ||||
| 		("spectate-skip-battle", "skip battles in spectator view") | ||||
| 		("spectate-skip-battle-result", "skip battle result window") | ||||
| 		("onlyAI", "allow one to run without human player, all players will be default AI") | ||||
| 		("headless", "runs without GUI, implies --onlyAI") | ||||
| 		("ai", po::value<std::vector<std::string>>(), "AI to be used for the player, can be specified several times for the consecutive players") | ||||
| 		("oneGoodAI", "puts one default AI and the rest will be EmptyAI") | ||||
| 		("autoSkip", "automatically skip turns in GUI") | ||||
| 		("disable-video", "disable video player") | ||||
| 		("nointro,i", "skips intro movies") | ||||
| 		("donotstartserver,d","do not attempt to start server and just connect to it instead server") | ||||
| 		("serverport", po::value<si64>(), "override port specified in config file") | ||||
| 		("savefrequency", po::value<si64>(), "limit auto save creation to each N days"); | ||||
|  | ||||
| 	if(argc > 1) | ||||
| 	{ | ||||
| 		try | ||||
| 		{ | ||||
| 			po::store(po::parse_command_line(argc, argv, opts, po_style::unix_style|po_style::case_insensitive), vm); | ||||
| 		} | ||||
| 		catch(boost::program_options::error &e) | ||||
| 		{ | ||||
| 			std::cerr << "Failure during parsing command-line options:\n" << e.what() << std::endl; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	po::notify(vm); | ||||
| 	if(vm.count("help")) | ||||
| 	{ | ||||
| 		prog_help(opts); | ||||
| #ifdef VCMI_IOS | ||||
| 		exit(0); | ||||
| #else | ||||
| 		return 0; | ||||
| #endif | ||||
| 	} | ||||
| 	if(vm.count("version")) | ||||
| 	{ | ||||
| 		prog_version(); | ||||
| #ifdef VCMI_IOS | ||||
| 		exit(0); | ||||
| #else | ||||
| 		return 0; | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
| 	// Init old logging system and new (temporary) logging system | ||||
| 	CStopWatch total; | ||||
| 	CStopWatch pomtime; | ||||
| 	std::cout.flags(std::ios::unitbuf); | ||||
| #ifndef VCMI_IOS | ||||
| 	console = new CConsoleHandler(); | ||||
|  | ||||
| 	auto callbackFunction = [](std::string buffer, bool calledFromIngameConsole) | ||||
| 	{ | ||||
| 		ClientCommandManager commandController; | ||||
| 		commandController.processCommand(buffer, calledFromIngameConsole); | ||||
| 	}; | ||||
|  | ||||
| 	*console->cb = callbackFunction; | ||||
| 	console->start(); | ||||
| #endif | ||||
|  | ||||
| 	setThreadNameLoggingOnly("MainGUI"); | ||||
| 	const boost::filesystem::path logPath = VCMIDirs::get().userLogsPath() / "VCMI_Client_log.txt"; | ||||
| 	logConfig = new CBasicLogConfigurator(logPath, console); | ||||
| 	logConfig->configureDefault(); | ||||
| 	logGlobal->info("Starting client of '%s'", GameConstants::VCMI_VERSION); | ||||
| 	logGlobal->info("Creating console and configuring logger: %d ms", pomtime.getDiff()); | ||||
| 	logGlobal->info("The log file will be saved to %s", logPath); | ||||
|  | ||||
| 	// Init filesystem and settings | ||||
| 	try | ||||
| 	{ | ||||
| 		preinitDLL(::console, false); | ||||
| 	} | ||||
| 	catch (const DataLoadingException & e) | ||||
| 	{ | ||||
| 		handleFatalError(e.what(), true); | ||||
| 	} | ||||
|  | ||||
| 	Settings session = settings.write["session"]; | ||||
| 	auto setSettingBool = [&](std::string key, std::string arg) { | ||||
| 		Settings s = settings.write(vstd::split(key, "/")); | ||||
| 		if(vm.count(arg)) | ||||
| 			s->Bool() = true; | ||||
| 		else if(s->isNull()) | ||||
| 			s->Bool() = false; | ||||
| 	}; | ||||
| 	auto setSettingInteger = [&](std::string key, std::string arg, si64 defaultValue) { | ||||
| 		Settings s = settings.write(vstd::split(key, "/")); | ||||
| 		if(vm.count(arg)) | ||||
| 			s->Integer() = vm[arg].as<si64>(); | ||||
| 		else if(s->isNull()) | ||||
| 			s->Integer() = defaultValue; | ||||
| 	}; | ||||
|  | ||||
| 	setSettingBool("session/onlyai", "onlyAI"); | ||||
| 	if(vm.count("headless")) | ||||
| 	{ | ||||
| 		session["headless"].Bool() = true; | ||||
| 		session["onlyai"].Bool() = true; | ||||
| 	} | ||||
| 	else if(vm.count("spectate")) | ||||
| 	{ | ||||
| 		session["spectate"].Bool() = true; | ||||
| 		session["spectate-ignore-hero"].Bool() = vm.count("spectate-ignore-hero"); | ||||
| 		session["spectate-skip-battle"].Bool() = vm.count("spectate-skip-battle"); | ||||
| 		session["spectate-skip-battle-result"].Bool() = vm.count("spectate-skip-battle-result"); | ||||
| 		if(vm.count("spectate-hero-speed")) | ||||
| 			session["spectate-hero-speed"].Integer() = vm["spectate-hero-speed"].as<int>(); | ||||
| 		if(vm.count("spectate-battle-speed")) | ||||
| 			session["spectate-battle-speed"].Float() = vm["spectate-battle-speed"].as<int>(); | ||||
| 	} | ||||
| 	// Server settings | ||||
| 	setSettingBool("session/donotstartserver", "donotstartserver"); | ||||
|  | ||||
| 	// Init special testing settings | ||||
| 	setSettingInteger("session/serverport", "serverport", 0); | ||||
| 	setSettingInteger("general/saveFrequency", "savefrequency", 1); | ||||
|  | ||||
| 	// Initialize logging based on settings | ||||
| 	logConfig->configure(); | ||||
| 	logGlobal->debug("settings = %s", settings.toJsonNode().toString()); | ||||
|  | ||||
| 	// Some basic data validation to produce better error messages in cases of incorrect install | ||||
| 	auto testFile = [](std::string filename, std::string message) | ||||
| 	{ | ||||
| 		if (!CResourceHandler::get()->existsResource(ResourcePath(filename))) | ||||
| 			handleFatalError(message, false); | ||||
| 	}; | ||||
|  | ||||
| 	testFile("DATA/HELP.TXT", "VCMI requires Heroes III: Shadow of Death or Heroes III: Complete data files to run!"); | ||||
| 	testFile("DATA/TENTCOLR.TXT", "Heroes III: Restoration of Erathia (including HD Edition) data files are not supported!"); | ||||
| 	testFile("MODS/VCMI/MOD.JSON", "VCMI installation is corrupted! Built-in mod was not found!"); | ||||
| 	testFile("DATA/PLAYERS.PAL", "Heroes III data files (Data/H3Bitmap.lod) are incomplete or corruped! Please reinstall them."); | ||||
| 	testFile("SPRITES/DEFAULT.DEF", "Heroes III data files (Data/H3Sprite.lod) are incomplete or corruped! Please reinstall them."); | ||||
|  | ||||
| 	srand ( (unsigned int)time(nullptr) ); | ||||
|  | ||||
| 	if(!settings["session"]["headless"].Bool()) | ||||
| 		GH.init(); | ||||
|  | ||||
| 	CCS = new CClientState(); | ||||
| 	CGI = new CGameInfo(); //contains all global information about game (texts, lodHandlers, map handler etc.) | ||||
| 	CSH = new CServerHandler(); | ||||
| 	 | ||||
| 	// Initialize video | ||||
| #ifdef DISABLE_VIDEO | ||||
| 	CCS->videoh = new CEmptyVideoPlayer(); | ||||
| #else | ||||
| 	if (!settings["session"]["headless"].Bool() && !vm.count("disable-video")) | ||||
| 		CCS->videoh = new CVideoPlayer(); | ||||
| 	else | ||||
| 		CCS->videoh = new CEmptyVideoPlayer(); | ||||
| #endif | ||||
|  | ||||
| 	logGlobal->info("\tInitializing video: %d ms", pomtime.getDiff()); | ||||
|  | ||||
| 	if(!settings["session"]["headless"].Bool()) | ||||
| 	{ | ||||
| 		//initializing audio | ||||
| 		CCS->soundh = new CSoundHandler(); | ||||
| 		CCS->soundh->setVolume((ui32)settings["general"]["sound"].Float()); | ||||
| 		CCS->musich = new CMusicHandler(); | ||||
| 		CCS->musich->setVolume((ui32)settings["general"]["music"].Float()); | ||||
| 		logGlobal->info("Initializing screen and sound handling: %d ms", pomtime.getDiff()); | ||||
| 	} | ||||
|  | ||||
| #ifndef VCMI_NO_THREADED_LOAD | ||||
| 	//we can properly play intro only in the main thread, so we have to move loading to the separate thread | ||||
| 	boost::thread loading([]() | ||||
| 	{ | ||||
| 		setThreadName("initialize"); | ||||
| 		init(); | ||||
| 	}); | ||||
| #else | ||||
| 	init(); | ||||
| #endif | ||||
|  | ||||
| 	if(!settings["session"]["headless"].Bool()) | ||||
| 	{ | ||||
| 		if(!vm.count("battle") && !vm.count("nointro") && settings["video"]["showIntro"].Bool()) | ||||
| 			playIntro(); | ||||
| 		GH.screenHandler().clearScreen(); | ||||
| 	} | ||||
|  | ||||
| #ifndef VCMI_NO_THREADED_LOAD | ||||
| 	#ifdef VCMI_ANDROID // android loads the data quite slowly so we display native progressbar to prevent having only black screen for few seconds | ||||
| 	{ | ||||
| 		CAndroidVMHelper vmHelper; | ||||
| 		vmHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "showProgress"); | ||||
| 	#endif // ANDROID | ||||
| 		loading.join(); | ||||
| 	#ifdef VCMI_ANDROID | ||||
| 		vmHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "hideProgress"); | ||||
| 	} | ||||
| 	#endif // ANDROID | ||||
| #endif // THREADED | ||||
|  | ||||
| 	if (criticalInitializationError.has_value()) | ||||
| 	{ | ||||
| 		handleFatalError(criticalInitializationError.value(), false); | ||||
| 	} | ||||
|  | ||||
| 	if(!settings["session"]["headless"].Bool()) | ||||
| 	{ | ||||
| 		pomtime.getDiff(); | ||||
| 		graphics = new Graphics(); // should be before curh | ||||
| 		GH.renderHandler().onLibraryLoadingFinished(CGI); | ||||
|  | ||||
| 		CCS->curh = new CursorHandler(); | ||||
| 		logGlobal->info("Screen handler: %d ms", pomtime.getDiff()); | ||||
|  | ||||
| 		CMessage::init(); | ||||
| 		logGlobal->info("Message handler: %d ms", pomtime.getDiff()); | ||||
|  | ||||
| 		CCS->curh->show(); | ||||
| 	} | ||||
|  | ||||
| 	logGlobal->info("Initialization of VCMI (together): %d ms", total.getDiff()); | ||||
|  | ||||
| 	session["autoSkip"].Bool()  = vm.count("autoSkip"); | ||||
| 	session["oneGoodAI"].Bool() = vm.count("oneGoodAI"); | ||||
| 	session["aiSolo"].Bool() = false; | ||||
| 	 | ||||
| 	if(vm.count("testmap")) | ||||
| 	{ | ||||
| 		session["testmap"].String() = vm["testmap"].as<std::string>(); | ||||
| 		session["onlyai"].Bool() = true; | ||||
| 		boost::thread(&CServerHandler::debugStartTest, CSH, session["testmap"].String(), false); | ||||
| 	} | ||||
| 	else if(vm.count("testsave")) | ||||
| 	{ | ||||
| 		session["testsave"].String() = vm["testsave"].as<std::string>(); | ||||
| 		session["onlyai"].Bool() = true; | ||||
| 		boost::thread(&CServerHandler::debugStartTest, CSH, session["testsave"].String(), true); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		auto mmenu = CMainMenu::create(); | ||||
| 		GH.curInt = mmenu.get(); | ||||
| 	} | ||||
| 	 | ||||
| 	std::vector<std::string> names; | ||||
|  | ||||
| 	if(!settings["session"]["headless"].Bool()) | ||||
| 	{ | ||||
| 		mainLoop(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		while(!headlessQuit) | ||||
| 			boost::this_thread::sleep_for(boost::chrono::milliseconds(200)); | ||||
|  | ||||
| 		boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); | ||||
|  | ||||
| 		quitApplication(); | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| //plays intro, ends when intro is over or button has been pressed (handles events) | ||||
| void playIntro() | ||||
| { | ||||
| 	if(!CCS->videoh->playIntroVideo(VideoPath::builtin("3DOLOGO.SMK"))) | ||||
| 		return; | ||||
|  | ||||
| 	if (!CCS->videoh->playIntroVideo(VideoPath::builtin("NWCLOGO.SMK"))) | ||||
| 		return; | ||||
|  | ||||
| 	CCS->videoh->playIntroVideo(VideoPath::builtin("H3INTRO.SMK")); | ||||
| } | ||||
|  | ||||
| static void mainLoop() | ||||
| { | ||||
| #ifndef VCMI_UNIX | ||||
| 	// on Linux, name of main thread is also name of our process. Which we don't want to change | ||||
| 	setThreadName("MainGUI"); | ||||
| #endif | ||||
|  | ||||
| 	while(1) //main SDL events loop | ||||
| 	{ | ||||
| 		GH.input().fetchEvents(); | ||||
| 		GH.renderFrame(); | ||||
| 	} | ||||
| } | ||||
| extern std::atomic<bool> headlessQuit; | ||||
| extern std::optional<std::string> criticalInitializationError; | ||||
| extern CBasicLogConfigurator *logConfig; | ||||
|  | ||||
| [[noreturn]] static void quitApplicationImmediately(int error_code) | ||||
| { | ||||
| @@ -442,7 +60,7 @@ static void mainLoop() | ||||
| #endif | ||||
| } | ||||
|  | ||||
| [[noreturn]] static void quitApplication() | ||||
| [[noreturn]] void quitApplication() | ||||
| { | ||||
| 	CSH->endNetwork(); | ||||
|  | ||||
|   | ||||
| @@ -25,3 +25,4 @@ 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(); | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| set(client_SRCS | ||||
| set(vcmiclientcommon_SRCS | ||||
| 	StdInc.cpp | ||||
| 	../CCallback.cpp | ||||
|  | ||||
| @@ -186,7 +186,7 @@ set(client_SRCS | ||||
| 	ServerRunner.cpp | ||||
| ) | ||||
|  | ||||
| set(client_HEADERS | ||||
| set(vcmiclientcommon_HEADERS | ||||
| 	StdInc.h | ||||
|  | ||||
| 	adventureMap/AdventureMapInterface.h | ||||
| @@ -396,14 +396,14 @@ set(client_HEADERS | ||||
| ) | ||||
|  | ||||
| if(APPLE_IOS) | ||||
| 	set(client_SRCS ${client_SRCS} | ||||
| 	set(vcmiclientcommon_SRCS ${vcmiclientcommon_SRCS} | ||||
| 		CFocusableHelper.cpp | ||||
| 		ios/GameChatKeyboardHandler.m | ||||
| 		ios/main.m | ||||
| 		ios/startSDL.mm | ||||
| 		ios/utils.mm | ||||
| 	) | ||||
| 	set(client_HEADERS ${client_HEADERS} | ||||
| 	set(vcmiclientcommon_HEADERS ${vcmiclientcommon_HEADERS} | ||||
| 		CFocusableHelper.h | ||||
| 		ios/GameChatKeyboardHandler.h | ||||
| 		ios/startSDL.h | ||||
| @@ -411,61 +411,51 @@ if(APPLE_IOS) | ||||
| 	) | ||||
| endif() | ||||
|  | ||||
| assign_source_group(${client_SRCS} ${client_HEADERS} VCMI_client.rc) | ||||
| assign_source_group(${vcmiclientcommon_SRCS} ${vcmiclientcommon_HEADERS} VCMI_vcmiclientcommon.rc) | ||||
|  | ||||
| if(ANDROID) | ||||
| 	add_library(vcmiclient SHARED ${client_SRCS} ${client_HEADERS}) | ||||
| 	set_target_properties(vcmiclient PROPERTIES | ||||
| 	add_library(vcmiclientcommon SHARED ${vcmiclientcommon_SRCS} ${vcmiclientcommon_HEADERS}) | ||||
| 	set_target_properties(vcmiclientcommon PROPERTIES | ||||
| 		OUTPUT_NAME "vcmiclient_${ANDROID_ABI}" # required by Qt | ||||
| 	) | ||||
| else() | ||||
| 	add_executable(vcmiclient ${client_SRCS} ${client_HEADERS}) | ||||
| 	add_library(vcmiclientcommon STATIC ${vcmiclientcommon_SRCS} ${vcmiclientcommon_HEADERS}) | ||||
| endif() | ||||
|  | ||||
| if(NOT ENABLE_STATIC_LIBS) | ||||
| 	add_dependencies(vcmiclient | ||||
| 	add_dependencies(vcmiclientcommon | ||||
| 		BattleAI | ||||
| 		EmptyAI | ||||
| 		StupidAI | ||||
| 		VCAI | ||||
| 	) | ||||
| 	if(ENABLE_NULLKILLER_AI) | ||||
| 		add_dependencies(vcmiclient Nullkiller) | ||||
| 		add_dependencies(vcmiclientcommon Nullkiller) | ||||
| 	endif() | ||||
| endif() | ||||
| if(APPLE_IOS) | ||||
| 	if(ENABLE_ERM) | ||||
| 		add_dependencies(vcmiclient vcmiERM) | ||||
| 		add_dependencies(vcmiclientcommon vcmiERM) | ||||
| 	endif() | ||||
| 	if(ENABLE_LUA) | ||||
| 		add_dependencies(vcmiclient vcmiLua) | ||||
| 		add_dependencies(vcmiclientcommon vcmiLua) | ||||
| 	endif() | ||||
| endif() | ||||
|  | ||||
| if(WIN32) | ||||
| 	target_sources(vcmiclient PRIVATE "VCMI_client.rc") | ||||
| 	set_target_properties(vcmiclient | ||||
| 	target_sources(vcmiclientcommon PRIVATE "VCMI_clientcommon.rc") | ||||
| 	set_target_properties(vcmiclientcommon | ||||
| 		PROPERTIES | ||||
| 			OUTPUT_NAME "VCMI_client" | ||||
| 			PROJECT_LABEL "VCMI_client" | ||||
| 			OUTPUT_NAME "VCMI_vcmiclientcommon" | ||||
| 			PROJECT_LABEL "VCMI_vcmiclientcommon" | ||||
| 	) | ||||
| 	set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT vcmiclient) | ||||
| 	set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT vcmiclientcommon) | ||||
| 	if(NOT ENABLE_DEBUG_CONSOLE) | ||||
| 		set_target_properties(vcmiclient PROPERTIES WIN32_EXECUTABLE) | ||||
| 		target_link_libraries(vcmiclient SDL2::SDL2main) | ||||
| 	endif() | ||||
| 	target_compile_definitions(vcmiclient PRIVATE WINDOWS_IGNORE_PACKING_MISMATCH) | ||||
|  | ||||
| # TODO: very hacky, find proper solution to copy AI dlls into bin dir | ||||
| 	if(MSVC) | ||||
| 		add_custom_command(TARGET vcmiclient POST_BUILD | ||||
| 			WORKING_DIRECTORY "$<TARGET_FILE_DIR:vcmiclient>" | ||||
| 			COMMAND ${CMAKE_COMMAND} -E copy AI/fuzzylite.dll fuzzylite.dll | ||||
| 			COMMAND ${CMAKE_COMMAND} -E copy AI/tbb12.dll tbb12.dll | ||||
| 		) | ||||
| 		target_link_libraries(vcmiclientcommon SDL2::SDL2main) | ||||
| 	endif() | ||||
| 	target_compile_definitions(vcmiclientcommon PRIVATE WINDOWS_IGNORE_PACKING_MISMATCH) | ||||
| elseif(APPLE_IOS) | ||||
| 	target_link_libraries(vcmiclient PRIVATE | ||||
| 	target_link_libraries(vcmiclientcommon PRIVATE | ||||
| 		iOS_utils | ||||
|  | ||||
| 		# FFmpeg | ||||
| @@ -478,16 +468,9 @@ elseif(APPLE_IOS) | ||||
| 		"-framework VideoToolbox" | ||||
| 	) | ||||
|  | ||||
| 	set_target_properties(vcmiclient PROPERTIES | ||||
| 		MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_LIST_DIR}/ios/Info.plist" | ||||
| 		XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks" | ||||
| 		XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "$(CODE_SIGNING_ALLOWED_FOR_APPS)" | ||||
| 		XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME AppIcon | ||||
| 	) | ||||
|  | ||||
| 	foreach(XCODE_RESOURCE LaunchScreen.storyboard Images.xcassets Settings.bundle vcmi_logo.png) | ||||
| 		set(XCODE_RESOURCE_PATH ios/${XCODE_RESOURCE}) | ||||
| 		target_sources(vcmiclient PRIVATE ${XCODE_RESOURCE_PATH}) | ||||
| 		target_sources(vcmiclientcommon PRIVATE ${XCODE_RESOURCE_PATH}) | ||||
| 		set_source_files_properties(${XCODE_RESOURCE_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) | ||||
|  | ||||
| 		# workaround to prevent CMAKE_SKIP_PRECOMPILE_HEADERS being added as compile flag | ||||
| @@ -495,83 +478,34 @@ elseif(APPLE_IOS) | ||||
| 			set_source_files_properties(${XCODE_RESOURCE_PATH} PROPERTIES LANGUAGE CXX) | ||||
| 		endif() | ||||
| 	endforeach() | ||||
|  | ||||
| 	set(CMAKE_EXE_LINKER_FLAGS "-Wl,-e,_client_main") | ||||
| endif() | ||||
|  | ||||
| target_link_libraries(vcmiclient PRIVATE vcmiservercommon) | ||||
| target_link_libraries(vcmiclientcommon PRIVATE vcmiservercommon) | ||||
| if(ENABLE_SINGLE_APP_BUILD AND ENABLE_LAUNCHER) | ||||
| 	target_link_libraries(vcmiclient PRIVATE vcmilauncher) | ||||
| 	target_link_libraries(vcmiclientcommon PRIVATE vcmilauncher) | ||||
| endif() | ||||
|  | ||||
| target_link_libraries(vcmiclient PRIVATE | ||||
| target_link_libraries(vcmiclientcommon PUBLIC | ||||
| 		vcmi SDL2::SDL2 SDL2::Image SDL2::Mixer SDL2::TTF | ||||
| ) | ||||
|  | ||||
| if(ffmpeg_LIBRARIES) | ||||
| 	target_link_libraries(vcmiclient PRIVATE | ||||
| 	target_link_libraries(vcmiclientcommon PRIVATE | ||||
| 		${ffmpeg_LIBRARIES} | ||||
| 	) | ||||
| else() | ||||
| 	target_compile_definitions(vcmiclient PRIVATE DISABLE_VIDEO) | ||||
| 	target_compile_definitions(vcmiclientcommon PRIVATE DISABLE_VIDEO) | ||||
| endif() | ||||
|  | ||||
| target_include_directories(vcmiclient PUBLIC | ||||
| target_include_directories(vcmiclientcommon PUBLIC | ||||
| 	${CMAKE_CURRENT_SOURCE_DIR} | ||||
| ) | ||||
|  | ||||
| if (ffmpeg_INCLUDE_DIRS) | ||||
| 	target_include_directories(vcmiclient PRIVATE | ||||
| 	target_include_directories(vcmiclientcommon PRIVATE | ||||
| 		${ffmpeg_INCLUDE_DIRS} | ||||
| 	) | ||||
| endif() | ||||
|  | ||||
| vcmi_set_output_dir(vcmiclient "") | ||||
| enable_pch(vcmiclient) | ||||
|  | ||||
| if(APPLE_IOS) | ||||
| 	vcmi_install_conan_deps("\${CMAKE_INSTALL_PREFIX}") | ||||
| 	add_custom_command(TARGET vcmiclient POST_BUILD | ||||
| 		COMMAND ios/set_build_version.sh "$<TARGET_BUNDLE_CONTENT_DIR:vcmiclient>" | ||||
| 		COMMAND ${CMAKE_COMMAND} --install "${CMAKE_BINARY_DIR}" --component "${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}" --config "$<CONFIG>" --prefix "$<TARGET_BUNDLE_CONTENT_DIR:vcmiclient>" | ||||
| 		COMMAND ios/rpath_remove_symlinks.sh | ||||
| 		COMMAND ios/codesign.sh | ||||
| 		WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | ||||
| 	) | ||||
| 	install(TARGETS vcmiclient DESTINATION Payload COMPONENT app) # for ipa generation with cpack | ||||
| elseif(ANDROID) | ||||
| 	find_program(androidDeployQt androiddeployqt | ||||
| 		PATHS "${qtBinDir}" | ||||
| 	) | ||||
| 	vcmi_install_conan_deps("\${CMAKE_INSTALL_PREFIX}/${LIB_DIR}") | ||||
|  | ||||
| 	add_custom_target(android_deploy ALL | ||||
| 		COMMAND ${CMAKE_COMMAND} --install "${CMAKE_BINARY_DIR}" --config "$<CONFIG>" --prefix "${androidQtBuildDir}" | ||||
| 		COMMAND "${androidDeployQt}" --input "${CMAKE_BINARY_DIR}/androiddeployqt.json" --output "${androidQtBuildDir}" --android-platform "android-${ANDROID_TARGET_SDK_VERSION}" --verbose $<$<NOT:$<CONFIG:Debug>>:--release> ${ANDROIDDEPLOYQT_OPTIONS} | ||||
| 		COMMAND_EXPAND_LISTS | ||||
| 		VERBATIM | ||||
| 		COMMENT "Create android package" | ||||
| 	) | ||||
| 	add_dependencies(android_deploy vcmiclient) | ||||
| else() | ||||
| 	install(TARGETS vcmiclient DESTINATION ${BIN_DIR}) | ||||
| endif() | ||||
|  | ||||
| #install icons and desktop file on Linux | ||||
| if(NOT WIN32 AND NOT APPLE AND NOT ANDROID) | ||||
| 	#FIXME: move to client makefile? | ||||
| 	foreach(iconSize 16 22 32 48 64 128 256 512 1024 2048) | ||||
| 		install(FILES "icons/vcmiclient.${iconSize}x${iconSize}.png" | ||||
| 			DESTINATION "share/icons/hicolor/${iconSize}x${iconSize}/apps" | ||||
| 			RENAME vcmiclient.png | ||||
| 		) | ||||
| 	endforeach() | ||||
|  | ||||
| 	install(FILES icons/vcmiclient.svg | ||||
| 		DESTINATION share/icons/hicolor/scalable/apps | ||||
| 		RENAME vcmiclient.svg | ||||
| 	) | ||||
| 	install(FILES icons/vcmiclient.desktop | ||||
| 		DESTINATION share/applications | ||||
| 	) | ||||
| endif() | ||||
| vcmi_set_output_dir(vcmiclientcommon "") | ||||
| enable_pch(vcmiclientcommon) | ||||
|   | ||||
| @@ -13,7 +13,6 @@ | ||||
| #include <vcmi/Artifact.h> | ||||
|  | ||||
| #include "CGameInfo.h" | ||||
| #include "CMT.h" | ||||
| #include "CServerHandler.h" | ||||
| #include "HeroMovementController.h" | ||||
| #include "PlayerLocalState.h" | ||||
|   | ||||
| @@ -38,7 +38,6 @@ | ||||
| #include "../lib/CHeroHandler.h" | ||||
| #include "../lib/VCMIDirs.h" | ||||
| #include "../lib/logging/VisualLogger.h" | ||||
| #include "CMT.h" | ||||
| #include "../lib/serializer/Connection.h" | ||||
|  | ||||
| #ifdef SCRIPTING_ENABLED | ||||
|   | ||||
| @@ -11,7 +11,6 @@ | ||||
| #include "StdInc.h" | ||||
| #include "InputSourceText.h" | ||||
|  | ||||
| #include "../CMT.h" | ||||
| #include "../gui/CGuiHandler.h" | ||||
| #include "../gui/EventDispatcher.h" | ||||
| #include "../render/IScreenHandler.h" | ||||
|   | ||||
| @@ -14,7 +14,6 @@ | ||||
| #include "InputHandler.h" | ||||
|  | ||||
| #include "../../lib/CConfigHandler.h" | ||||
| #include "../CMT.h" | ||||
| #include "../CGameInfo.h" | ||||
| #include "../gui/CursorHandler.h" | ||||
| #include "../gui/CGuiHandler.h" | ||||
|   | ||||
							
								
								
									
										100
									
								
								clientapp/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								clientapp/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| set(clientapp_SRCS | ||||
|     StdInc.cpp | ||||
|     EntryPoint.cpp | ||||
| ) | ||||
|  | ||||
| set(clientapp_HEADERS | ||||
|     StdInc.h | ||||
| ) | ||||
|  | ||||
| assign_source_group(${clientapp_SRCS} ${clientapp_HEADERS}) | ||||
| add_executable(vcmiclient ${clientapp_SRCS} ${clientapp_HEADERS}) | ||||
|  | ||||
| target_link_libraries(vcmiclient PRIVATE vcmiclientcommon) | ||||
|  | ||||
| target_include_directories(vcmiclient | ||||
|   PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} | ||||
| ) | ||||
|  | ||||
| if(WIN32) | ||||
|   target_sources(vcmiclient PRIVATE "VCMI_client.rc") | ||||
|   set_target_properties(vcmiclient | ||||
|     PROPERTIES | ||||
|       OUTPUT_NAME "VCMI_client" | ||||
|       PROJECT_LABEL "VCMI_client" | ||||
|   ) | ||||
|   set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT vcmiclient) | ||||
|   if(NOT ENABLE_DEBUG_CONSOLE) | ||||
|     set_target_properties(vcmiclient PROPERTIES WIN32_EXECUTABLE) | ||||
|     target_link_libraries(vcmiclient SDL2::SDL2main) | ||||
|   endif() | ||||
|   target_compile_definitions(vcmiclient PRIVATE WINDOWS_IGNORE_PACKING_MISMATCH) | ||||
|  | ||||
| # TODO: very hacky, find proper solution to copy AI dlls into bin dir | ||||
|   if(MSVC) | ||||
|     add_custom_command(TARGET vcmiclient POST_BUILD | ||||
|       WORKING_DIRECTORY "$<TARGET_FILE_DIR:vcmiclient>" | ||||
|       COMMAND ${CMAKE_COMMAND} -E copy AI/fuzzylite.dll fuzzylite.dll | ||||
|       COMMAND ${CMAKE_COMMAND} -E copy AI/tbb12.dll tbb12.dll | ||||
|     ) | ||||
|   endif() | ||||
| elseif(APPLE_IOS) | ||||
|   set_target_properties(vcmiclient PROPERTIES | ||||
|     MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_LIST_DIR}/ios/Info.plist" | ||||
|     XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks" | ||||
|     XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "$(CODE_SIGNING_ALLOWED_FOR_APPS)" | ||||
|     XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME AppIcon | ||||
|   ) | ||||
|  | ||||
|   set(CMAKE_EXE_LINKER_FLAGS "-Wl,-e,_vcmiclient_main") | ||||
| endif() | ||||
|  | ||||
| vcmi_set_output_dir(vcmiclient "") | ||||
| enable_pch(vcmiclient) | ||||
|  | ||||
| if(APPLE_IOS) | ||||
|   vcmi_install_conan_deps("\${CMAKE_INSTALL_PREFIX}") | ||||
|   add_custom_command(TARGET vcmiclient POST_BUILD | ||||
|     COMMAND ios/set_build_version.sh "$<TARGET_BUNDLE_CONTENT_DIR:vcmiclient>" | ||||
|     COMMAND ${CMAKE_COMMAND} --install "${CMAKE_BINARY_DIR}" --component "${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}" --config "$<CONFIG>" --prefix "$<TARGET_BUNDLE_CONTENT_DIR:vcmiclient>" | ||||
|     COMMAND ios/rpath_remove_symlinks.sh | ||||
|     COMMAND ios/codesign.sh | ||||
|     WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | ||||
|   ) | ||||
|   install(TARGETS vcmiclient DESTINATION Payload COMPONENT app) # for ipa generation with cpack | ||||
| elseif(ANDROID) | ||||
|   find_program(androidDeployQt androiddeployqt | ||||
|     PATHS "${qtBinDir}" | ||||
|   ) | ||||
|   vcmi_install_conan_deps("\${CMAKE_INSTALL_PREFIX}/${LIB_DIR}") | ||||
|  | ||||
|   add_custom_target(android_deploy ALL | ||||
|     COMMAND ${CMAKE_COMMAND} --install "${CMAKE_BINARY_DIR}" --config "$<CONFIG>" --prefix "${androidQtBuildDir}" | ||||
|     COMMAND "${androidDeployQt}" --input "${CMAKE_BINARY_DIR}/androiddeployqt.json" --output "${androidQtBuildDir}" --android-platform "android-${ANDROID_TARGET_SDK_VERSION}" --verbose $<$<NOT:$<CONFIG:Debug>>:--release> ${ANDROIDDEPLOYQT_OPTIONS} | ||||
|     COMMAND_EXPAND_LISTS | ||||
|     VERBATIM | ||||
|     COMMENT "Create android package" | ||||
|   ) | ||||
|   add_dependencies(android_deploy vcmiclient) | ||||
| else() | ||||
|   install(TARGETS vcmiclient DESTINATION ${BIN_DIR}) | ||||
| endif() | ||||
|  | ||||
| #install icons and desktop file on Linux | ||||
| if(NOT WIN32 AND NOT APPLE AND NOT ANDROID) | ||||
|   #FIXME: move to client makefile? | ||||
|   foreach(iconSize 16 22 32 48 64 128 256 512 1024 2048) | ||||
|     install(FILES "icons/vcmiclient.${iconSize}x${iconSize}.png" | ||||
|       DESTINATION "share/icons/hicolor/${iconSize}x${iconSize}/apps" | ||||
|       RENAME vcmiclient.png | ||||
|     ) | ||||
|   endforeach() | ||||
|  | ||||
|   install(FILES icons/vcmiclient.svg | ||||
|     DESTINATION share/icons/hicolor/scalable/apps | ||||
|     RENAME vcmiclient.svg | ||||
|   ) | ||||
|   install(FILES icons/vcmiclient.desktop | ||||
|     DESTINATION share/applications | ||||
|   ) | ||||
| endif() | ||||
							
								
								
									
										424
									
								
								clientapp/EntryPoint.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										424
									
								
								clientapp/EntryPoint.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,424 @@ | ||||
| /* | ||||
|  * EntryPoint.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 | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| // 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 "../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 <boost/program_options.hpp> | ||||
| #include <vstd/StringUtils.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 | ||||
|  | ||||
| namespace po = boost::program_options; | ||||
| namespace po_style = boost::program_options::command_line_style; | ||||
|  | ||||
| std::atomic<bool> headlessQuit = false; | ||||
| std::optional<std::string> criticalInitializationError; | ||||
|  | ||||
| #ifndef VCMI_IOS | ||||
| void processCommand(const std::string &message); | ||||
| #endif | ||||
| void playIntro(); | ||||
| static void mainLoop(); | ||||
|  | ||||
| CBasicLogConfigurator *logConfig; | ||||
|  | ||||
| void init() | ||||
| { | ||||
| 	CStopWatch tmh; | ||||
| 	try | ||||
| 	{ | ||||
| 		loadDLLClasses(); | ||||
| 		CGI->setFromLib(); | ||||
| 	} | ||||
| 	catch (const DataLoadingException & e) | ||||
| 	{ | ||||
| 		criticalInitializationError = e.what(); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	logGlobal->info("Initializing VCMI_Lib: %d ms", tmh.getDiff()); | ||||
|  | ||||
| 	// Debug code to load all maps on start | ||||
| 	//ClientCommandManager commandController; | ||||
| 	//commandController.processCommand("convert txt", false); | ||||
| } | ||||
|  | ||||
| static void prog_version() | ||||
| { | ||||
| 	printf("%s\n", GameConstants::VCMI_VERSION.c_str()); | ||||
| 	std::cout << VCMIDirs::get().genHelpString(); | ||||
| } | ||||
|  | ||||
| static void prog_help(const po::options_description &opts) | ||||
| { | ||||
| 	auto time = std::time(nullptr); | ||||
| 	printf("%s - A Heroes of Might and Magic 3 clone\n", GameConstants::VCMI_VERSION.c_str()); | ||||
| 	printf("Copyright (C) 2007-%d VCMI dev team - see AUTHORS file\n", std::localtime(&time)->tm_year + 1900); | ||||
| 	printf("This is free software; see the source for copying conditions. There is NO\n"); | ||||
| 	printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); | ||||
| 	printf("\n"); | ||||
| 	std::cout << opts; | ||||
| } | ||||
|  | ||||
| #if defined(VCMI_WINDOWS) && !defined(__GNUC__) && defined(VCMI_WITH_DEBUG_CONSOLE) | ||||
| int wmain(int argc, wchar_t* argv[]) | ||||
| #elif defined(VCMI_MOBILE) | ||||
| int SDL_main(int argc, char *argv[]) | ||||
| #else | ||||
| int main(int argc, char * argv[]) | ||||
| #endif | ||||
| { | ||||
| #ifdef VCMI_ANDROID | ||||
| 	CAndroidVMHelper::initClassloader(SDL_AndroidGetJNIEnv()); | ||||
| 	// boost will crash without this | ||||
| 	setenv("LANG", "C", 1); | ||||
| #endif | ||||
|  | ||||
| #if !defined(VCMI_MOBILE) | ||||
| 	// Correct working dir executable folder (not bundle folder) so we can use executable relative paths | ||||
| 	boost::filesystem::current_path(boost::filesystem::system_complete(argv[0]).parent_path()); | ||||
| #endif | ||||
| 	std::cout << "Starting... " << std::endl; | ||||
| 	po::options_description opts("Allowed options"); | ||||
| 	po::variables_map vm; | ||||
|  | ||||
| 	opts.add_options() | ||||
| 		("help,h", "display help and exit") | ||||
| 		("version,v", "display version information and exit") | ||||
| 		("testmap", po::value<std::string>(), "") | ||||
| 		("testsave", po::value<std::string>(), "") | ||||
| 		("spectate,s", "enable spectator interface for AI-only games") | ||||
| 		("spectate-ignore-hero", "wont follow heroes on adventure map") | ||||
| 		("spectate-hero-speed", po::value<int>(), "hero movement speed on adventure map") | ||||
| 		("spectate-battle-speed", po::value<int>(), "battle animation speed for spectator") | ||||
| 		("spectate-skip-battle", "skip battles in spectator view") | ||||
| 		("spectate-skip-battle-result", "skip battle result window") | ||||
| 		("onlyAI", "allow one to run without human player, all players will be default AI") | ||||
| 		("headless", "runs without GUI, implies --onlyAI") | ||||
| 		("ai", po::value<std::vector<std::string>>(), "AI to be used for the player, can be specified several times for the consecutive players") | ||||
| 		("oneGoodAI", "puts one default AI and the rest will be EmptyAI") | ||||
| 		("autoSkip", "automatically skip turns in GUI") | ||||
| 		("disable-video", "disable video player") | ||||
| 		("nointro,i", "skips intro movies") | ||||
| 		("donotstartserver,d","do not attempt to start server and just connect to it instead server") | ||||
| 		("serverport", po::value<si64>(), "override port specified in config file") | ||||
| 		("savefrequency", po::value<si64>(), "limit auto save creation to each N days"); | ||||
|  | ||||
| 	if(argc > 1) | ||||
| 	{ | ||||
| 		try | ||||
| 		{ | ||||
| 			po::store(po::parse_command_line(argc, argv, opts, po_style::unix_style|po_style::case_insensitive), vm); | ||||
| 		} | ||||
| 		catch(boost::program_options::error &e) | ||||
| 		{ | ||||
| 			std::cerr << "Failure during parsing command-line options:\n" << e.what() << std::endl; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	po::notify(vm); | ||||
| 	if(vm.count("help")) | ||||
| 	{ | ||||
| 		prog_help(opts); | ||||
| #ifdef VCMI_IOS | ||||
| 		exit(0); | ||||
| #else | ||||
| 		return 0; | ||||
| #endif | ||||
| 	} | ||||
| 	if(vm.count("version")) | ||||
| 	{ | ||||
| 		prog_version(); | ||||
| #ifdef VCMI_IOS | ||||
| 		exit(0); | ||||
| #else | ||||
| 		return 0; | ||||
| #endif | ||||
| 	} | ||||
|  | ||||
| 	// Init old logging system and new (temporary) logging system | ||||
| 	CStopWatch total; | ||||
| 	CStopWatch pomtime; | ||||
| 	std::cout.flags(std::ios::unitbuf); | ||||
| #ifndef VCMI_IOS | ||||
| 	console = new CConsoleHandler(); | ||||
|  | ||||
| 	auto callbackFunction = [](std::string buffer, bool calledFromIngameConsole) | ||||
| 	{ | ||||
| 		ClientCommandManager commandController; | ||||
| 		commandController.processCommand(buffer, calledFromIngameConsole); | ||||
| 	}; | ||||
|  | ||||
| 	*console->cb = callbackFunction; | ||||
| 	console->start(); | ||||
| #endif | ||||
|  | ||||
| 	setThreadNameLoggingOnly("MainGUI"); | ||||
| 	const boost::filesystem::path logPath = VCMIDirs::get().userLogsPath() / "VCMI_Client_log.txt"; | ||||
| 	logConfig = new CBasicLogConfigurator(logPath, console); | ||||
| 	logConfig->configureDefault(); | ||||
| 	logGlobal->info("Starting client of '%s'", GameConstants::VCMI_VERSION); | ||||
| 	logGlobal->info("Creating console and configuring logger: %d ms", pomtime.getDiff()); | ||||
| 	logGlobal->info("The log file will be saved to %s", logPath); | ||||
|  | ||||
| 	// Init filesystem and settings | ||||
| 	try | ||||
| 	{ | ||||
| 		preinitDLL(::console, false); | ||||
| 	} | ||||
| 	catch (const DataLoadingException & e) | ||||
| 	{ | ||||
| 		handleFatalError(e.what(), true); | ||||
| 	} | ||||
|  | ||||
| 	Settings session = settings.write["session"]; | ||||
| 	auto setSettingBool = [&](std::string key, std::string arg) { | ||||
| 		Settings s = settings.write(vstd::split(key, "/")); | ||||
| 		if(vm.count(arg)) | ||||
| 			s->Bool() = true; | ||||
| 		else if(s->isNull()) | ||||
| 			s->Bool() = false; | ||||
| 	}; | ||||
| 	auto setSettingInteger = [&](std::string key, std::string arg, si64 defaultValue) { | ||||
| 		Settings s = settings.write(vstd::split(key, "/")); | ||||
| 		if(vm.count(arg)) | ||||
| 			s->Integer() = vm[arg].as<si64>(); | ||||
| 		else if(s->isNull()) | ||||
| 			s->Integer() = defaultValue; | ||||
| 	}; | ||||
|  | ||||
| 	setSettingBool("session/onlyai", "onlyAI"); | ||||
| 	if(vm.count("headless")) | ||||
| 	{ | ||||
| 		session["headless"].Bool() = true; | ||||
| 		session["onlyai"].Bool() = true; | ||||
| 	} | ||||
| 	else if(vm.count("spectate")) | ||||
| 	{ | ||||
| 		session["spectate"].Bool() = true; | ||||
| 		session["spectate-ignore-hero"].Bool() = vm.count("spectate-ignore-hero"); | ||||
| 		session["spectate-skip-battle"].Bool() = vm.count("spectate-skip-battle"); | ||||
| 		session["spectate-skip-battle-result"].Bool() = vm.count("spectate-skip-battle-result"); | ||||
| 		if(vm.count("spectate-hero-speed")) | ||||
| 			session["spectate-hero-speed"].Integer() = vm["spectate-hero-speed"].as<int>(); | ||||
| 		if(vm.count("spectate-battle-speed")) | ||||
| 			session["spectate-battle-speed"].Float() = vm["spectate-battle-speed"].as<int>(); | ||||
| 	} | ||||
| 	// Server settings | ||||
| 	setSettingBool("session/donotstartserver", "donotstartserver"); | ||||
|  | ||||
| 	// Init special testing settings | ||||
| 	setSettingInteger("session/serverport", "serverport", 0); | ||||
| 	setSettingInteger("general/saveFrequency", "savefrequency", 1); | ||||
|  | ||||
| 	// Initialize logging based on settings | ||||
| 	logConfig->configure(); | ||||
| 	logGlobal->debug("settings = %s", settings.toJsonNode().toString()); | ||||
|  | ||||
| 	// Some basic data validation to produce better error messages in cases of incorrect install | ||||
| 	auto testFile = [](std::string filename, std::string message) | ||||
| 	{ | ||||
| 		if (!CResourceHandler::get()->existsResource(ResourcePath(filename))) | ||||
| 			handleFatalError(message, false); | ||||
| 	}; | ||||
|  | ||||
| 	testFile("DATA/HELP.TXT", "VCMI requires Heroes III: Shadow of Death or Heroes III: Complete data files to run!"); | ||||
| 	testFile("DATA/TENTCOLR.TXT", "Heroes III: Restoration of Erathia (including HD Edition) data files are not supported!"); | ||||
| 	testFile("MODS/VCMI/MOD.JSON", "VCMI installation is corrupted! Built-in mod was not found!"); | ||||
| 	testFile("DATA/PLAYERS.PAL", "Heroes III data files (Data/H3Bitmap.lod) are incomplete or corruped! Please reinstall them."); | ||||
| 	testFile("SPRITES/DEFAULT.DEF", "Heroes III data files (Data/H3Sprite.lod) are incomplete or corruped! Please reinstall them."); | ||||
|  | ||||
| 	srand ( (unsigned int)time(nullptr) ); | ||||
|  | ||||
| 	if(!settings["session"]["headless"].Bool()) | ||||
| 		GH.init(); | ||||
|  | ||||
| 	CCS = new CClientState(); | ||||
| 	CGI = new CGameInfo(); //contains all global information about game (texts, lodHandlers, map handler etc.) | ||||
| 	CSH = new CServerHandler(); | ||||
| 	 | ||||
| 	// Initialize video | ||||
| #ifdef DISABLE_VIDEO | ||||
| 	CCS->videoh = new CEmptyVideoPlayer(); | ||||
| #else | ||||
| 	if (!settings["session"]["headless"].Bool() && !vm.count("disable-video")) | ||||
| 		CCS->videoh = new CVideoPlayer(); | ||||
| 	else | ||||
| 		CCS->videoh = new CEmptyVideoPlayer(); | ||||
| #endif | ||||
|  | ||||
| 	logGlobal->info("\tInitializing video: %d ms", pomtime.getDiff()); | ||||
|  | ||||
| 	if(!settings["session"]["headless"].Bool()) | ||||
| 	{ | ||||
| 		//initializing audio | ||||
| 		CCS->soundh = new CSoundHandler(); | ||||
| 		CCS->soundh->setVolume((ui32)settings["general"]["sound"].Float()); | ||||
| 		CCS->musich = new CMusicHandler(); | ||||
| 		CCS->musich->setVolume((ui32)settings["general"]["music"].Float()); | ||||
| 		logGlobal->info("Initializing screen and sound handling: %d ms", pomtime.getDiff()); | ||||
| 	} | ||||
|  | ||||
| #ifndef VCMI_NO_THREADED_LOAD | ||||
| 	//we can properly play intro only in the main thread, so we have to move loading to the separate thread | ||||
| 	boost::thread loading([]() | ||||
| 	{ | ||||
| 		setThreadName("initialize"); | ||||
| 		init(); | ||||
| 	}); | ||||
| #else | ||||
| 	init(); | ||||
| #endif | ||||
|  | ||||
| 	if(!settings["session"]["headless"].Bool()) | ||||
| 	{ | ||||
| 		if(!vm.count("battle") && !vm.count("nointro") && settings["video"]["showIntro"].Bool()) | ||||
| 			playIntro(); | ||||
| 		GH.screenHandler().clearScreen(); | ||||
| 	} | ||||
|  | ||||
| #ifndef VCMI_NO_THREADED_LOAD | ||||
| 	#ifdef VCMI_ANDROID // android loads the data quite slowly so we display native progressbar to prevent having only black screen for few seconds | ||||
| 	{ | ||||
| 		CAndroidVMHelper vmHelper; | ||||
| 		vmHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "showProgress"); | ||||
| 	#endif // ANDROID | ||||
| 		loading.join(); | ||||
| 	#ifdef VCMI_ANDROID | ||||
| 		vmHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "hideProgress"); | ||||
| 	} | ||||
| 	#endif // ANDROID | ||||
| #endif // THREADED | ||||
|  | ||||
| 	if (criticalInitializationError.has_value()) | ||||
| 	{ | ||||
| 		handleFatalError(criticalInitializationError.value(), false); | ||||
| 	} | ||||
|  | ||||
| 	if(!settings["session"]["headless"].Bool()) | ||||
| 	{ | ||||
| 		pomtime.getDiff(); | ||||
| 		graphics = new Graphics(); // should be before curh | ||||
| 		GH.renderHandler().onLibraryLoadingFinished(CGI); | ||||
|  | ||||
| 		CCS->curh = new CursorHandler(); | ||||
| 		logGlobal->info("Screen handler: %d ms", pomtime.getDiff()); | ||||
|  | ||||
| 		CMessage::init(); | ||||
| 		logGlobal->info("Message handler: %d ms", pomtime.getDiff()); | ||||
|  | ||||
| 		CCS->curh->show(); | ||||
| 	} | ||||
|  | ||||
| 	logGlobal->info("Initialization of VCMI (together): %d ms", total.getDiff()); | ||||
|  | ||||
| 	session["autoSkip"].Bool()  = vm.count("autoSkip"); | ||||
| 	session["oneGoodAI"].Bool() = vm.count("oneGoodAI"); | ||||
| 	session["aiSolo"].Bool() = false; | ||||
| 	 | ||||
| 	if(vm.count("testmap")) | ||||
| 	{ | ||||
| 		session["testmap"].String() = vm["testmap"].as<std::string>(); | ||||
| 		session["onlyai"].Bool() = true; | ||||
| 		boost::thread(&CServerHandler::debugStartTest, CSH, session["testmap"].String(), false); | ||||
| 	} | ||||
| 	else if(vm.count("testsave")) | ||||
| 	{ | ||||
| 		session["testsave"].String() = vm["testsave"].as<std::string>(); | ||||
| 		session["onlyai"].Bool() = true; | ||||
| 		boost::thread(&CServerHandler::debugStartTest, CSH, session["testsave"].String(), true); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		auto mmenu = CMainMenu::create(); | ||||
| 		GH.curInt = mmenu.get(); | ||||
| 	} | ||||
| 	 | ||||
| 	std::vector<std::string> names; | ||||
|  | ||||
| 	if(!settings["session"]["headless"].Bool()) | ||||
| 	{ | ||||
| 		mainLoop(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		while(!headlessQuit) | ||||
| 			boost::this_thread::sleep_for(boost::chrono::milliseconds(200)); | ||||
|  | ||||
| 		boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); | ||||
|  | ||||
| 		quitApplication(); | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| //plays intro, ends when intro is over or button has been pressed (handles events) | ||||
| void playIntro() | ||||
| { | ||||
| 	if(!CCS->videoh->playIntroVideo(VideoPath::builtin("3DOLOGO.SMK"))) | ||||
| 		return; | ||||
|  | ||||
| 	if (!CCS->videoh->playIntroVideo(VideoPath::builtin("NWCLOGO.SMK"))) | ||||
| 		return; | ||||
|  | ||||
| 	CCS->videoh->playIntroVideo(VideoPath::builtin("H3INTRO.SMK")); | ||||
| } | ||||
|  | ||||
| static void mainLoop() | ||||
| { | ||||
| #ifndef VCMI_UNIX | ||||
| 	// on Linux, name of main thread is also name of our process. Which we don't want to change | ||||
| 	setThreadName("MainGUI"); | ||||
| #endif | ||||
|  | ||||
| 	while(1) //main SDL events loop | ||||
| 	{ | ||||
| 		GH.input().fetchEvents(); | ||||
| 		GH.renderFrame(); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										11
									
								
								clientapp/StdInc.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								clientapp/StdInc.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| /* | ||||
|  * StdInc.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 | ||||
|  * | ||||
|  */ | ||||
| // Creates the precompiled header | ||||
| #include "StdInc.h" | ||||
							
								
								
									
										14
									
								
								clientapp/StdInc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								clientapp/StdInc.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| /* | ||||
|  * StdInc.h, 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 | ||||
|  * | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include "../Global.h" | ||||
|  | ||||
| VCMI_LIB_USING_NAMESPACE | ||||
		Reference in New Issue
	
	Block a user