X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fsupertux%2Fmain.cpp;h=17571a3c8c2a5c8bb411e595b8cbc4a6df22f5bd;hb=c0e497c19521c1868f44c0fd21bbf666a66654be;hp=75c7544255c5dcfdb7c694c8708acae40303f438;hpb=8bd7a82e3f24faa2a708acf1c10500098c6491db;p=supertux.git diff --git a/src/supertux/main.cpp b/src/supertux/main.cpp index 75c754425..17571a3c8 100644 --- a/src/supertux/main.cpp +++ b/src/supertux/main.cpp @@ -20,12 +20,12 @@ #include #include -#include -#include -#include -#include #include +#include +#include +#include #include +#include extern "C" { #include } @@ -38,10 +38,12 @@ extern "C" { #include "physfs/physfs_file_system.hpp" #include "physfs/physfs_sdl.hpp" #include "scripting/squirrel_util.hpp" +#include "scripting/scripting.hpp" +#include "sprite/sprite_manager.hpp" +#include "supertux/command_line_arguments.hpp" #include "supertux/game_manager.hpp" #include "supertux/gameconfig.hpp" #include "supertux/globals.hpp" -#include "supertux/command_line_arguments.hpp" #include "supertux/player_status.hpp" #include "supertux/resources.hpp" #include "supertux/screen_fade.hpp" @@ -54,165 +56,208 @@ extern "C" { #include "video/renderer.hpp" #include "worldmap/worldmap.hpp" -namespace { DrawingContext *context_pointer; } - -void -Main::init_config() +class ConfigSubsystem { - g_config = new Config(); - try { - g_config->load(); - } catch(std::exception& e) { - log_info << "Couldn't load config file: " << e.what() << ", using default settings" << std::endl; +public: + ConfigSubsystem() + { + g_config.reset(new Config); + try { + g_config->load(); + } + catch(const std::exception& e) + { + log_info << "Couldn't load config file: " << e.what() << ", using default settings" << std::endl; + } + + // init random number stuff + g_config->random_seed = gameRandom.srand(g_config->random_seed); + graphicsRandom.srand(0); + //const char *how = config->random_seed? ", user fixed.": ", from time()."; + //log_info << "Using random seed " << config->random_seed << how << std::endl; } -} + + ~ConfigSubsystem() + { + if (g_config) + { + g_config->save(); + } + g_config.reset(); + } +}; void Main::init_tinygettext() { - dictionary_manager = new tinygettext::DictionaryManager(); + g_dictionary_manager.reset(new tinygettext::DictionaryManager); tinygettext::Log::set_log_info_callback(0); - dictionary_manager->set_filesystem(std::unique_ptr(new PhysFSFileSystem)); + g_dictionary_manager->set_filesystem(std::unique_ptr(new PhysFSFileSystem)); - dictionary_manager->add_directory("locale"); - dictionary_manager->set_charset("UTF-8"); + g_dictionary_manager->add_directory("locale"); + g_dictionary_manager->set_charset("UTF-8"); // Config setting "locale" overrides language detection if (g_config->locale != "") { - dictionary_manager->set_language(tinygettext::Language::from_name(g_config->locale)); - } else { + g_dictionary_manager->set_language(tinygettext::Language::from_name(g_config->locale)); + } + else + { FL_Locale *locale; FL_FindLocale(&locale); tinygettext::Language language = tinygettext::Language::from_spec( locale->lang?locale->lang:"", locale->country?locale->country:"", locale->variant?locale->variant:""); FL_FreeLocale(&locale); - dictionary_manager->set_language(language); + g_dictionary_manager->set_language(language); } } -void -Main::init_physfs(const char* argv0) +class PhysfsSubsystem { - if(!PHYSFS_init(argv0)) { - std::stringstream msg; - msg << "Couldn't initialize physfs: " << PHYSFS_getLastError(); - throw std::runtime_error(msg.str()); - } - - // allow symbolic links - PHYSFS_permitSymbolicLinks(1); - - // Initialize physfs (this is a slightly modified version of - // PHYSFS_setSaneConfig) - const char *env_writedir; - std::string writedir; - - if ((env_writedir = getenv("SUPERTUX2_USER_DIR")) != NULL) { - writedir = env_writedir; - if(!PHYSFS_setWriteDir(writedir.c_str())) { - std::ostringstream msg; - msg << "Failed to use configuration directory '" - << writedir << "': " << PHYSFS_getLastError(); +private: + boost::optional m_forced_datadir; + boost::optional m_forced_userdir; + +public: + PhysfsSubsystem(const char* argv0, + boost::optional forced_datadir, + boost::optional forced_userdir) : + m_forced_datadir(forced_datadir), + m_forced_userdir(forced_userdir) + { + if (!PHYSFS_init(argv0)) + { + std::stringstream msg; + msg << "Couldn't initialize physfs: " << PHYSFS_getLastError(); throw std::runtime_error(msg.str()); } + else + { + // allow symbolic links + PHYSFS_permitSymbolicLinks(1); - } else { - std::string userdir = PHYSFS_getUserDir(); - - // Set configuration directory - writedir = userdir + WRITEDIR_NAME; - if(!PHYSFS_setWriteDir(writedir.c_str())) { - // try to create the directory - if(!PHYSFS_setWriteDir(userdir.c_str()) || !PHYSFS_mkdir(WRITEDIR_NAME)) { - std::ostringstream msg; - msg << "Failed creating configuration directory '" - << writedir << "': " << PHYSFS_getLastError(); - throw std::runtime_error(msg.str()); - } + find_userdir(); + find_datadir(); + } + } - if(!PHYSFS_setWriteDir(writedir.c_str())) { - std::ostringstream msg; - msg << "Failed to use configuration directory '" - << writedir << "': " << PHYSFS_getLastError(); - throw std::runtime_error(msg.str()); + void find_datadir() + { + std::string datadir; + if (m_forced_datadir) + { + datadir = *m_forced_datadir; + } + else if (const char* env_datadir = getenv("SUPERTUX2_DATA_DIR")) + { + datadir = env_datadir; + } + else + { + // check if we run from source dir + char* basepath_c = SDL_GetBasePath(); + std::string basepath = basepath_c; + SDL_free(basepath_c); + + datadir = FileSystem::join(basepath, "data"); + std::string testfname = FileSystem::join(datadir, "credits.txt"); + if (!FileSystem::exists(testfname)) + { + // if the game is not run from the source directory, try to find + // the global install location + datadir = datadir.substr(0, datadir.rfind(INSTALL_SUBDIR_BIN)); + datadir = FileSystem::join(datadir, INSTALL_SUBDIR_SHARE); } } - } - PHYSFS_addToSearchPath(writedir.c_str(), 0); - - // when started from source dir... - char* base_path = SDL_GetBasePath(); - std::string dir = base_path; - SDL_free(base_path); - - if (dir[dir.length() - 1] != '/') - dir += "/"; - dir += "data"; - std::string testfname = dir; - testfname += "/credits.txt"; - bool sourcedir = false; - FILE* f = fopen(testfname.c_str(), "r"); - if(f) { - fclose(f); - if(!PHYSFS_addToSearchPath(dir.c_str(), 1)) { - log_warning << "Couldn't add '" << dir << "' to physfs searchpath: " << PHYSFS_getLastError() << std::endl; - } else { - sourcedir = true; + + if (!PHYSFS_addToSearchPath(datadir.c_str(), 1)) + { + log_warning << "Couldn't add '" << datadir << "' to physfs searchpath: " << PHYSFS_getLastError() << std::endl; } } - if(!sourcedir) { - std::string datadir = PHYSFS_getBaseDir(); - datadir = datadir.substr(0, datadir.rfind(INSTALL_SUBDIR_BIN)); - datadir += "/" INSTALL_SUBDIR_SHARE; -#ifdef ENABLE_BINRELOC + void find_userdir() + { + std::string userdir; + if (m_forced_userdir) + { + userdir = *m_forced_userdir; + } + else if (const char* env_userdir = getenv("SUPERTUX2_USER_DIR")) + { + userdir = env_userdir; + } + else + { + std::string physfs_userdir = PHYSFS_getUserDir(); +#ifdef _WIN32 + userdir = FileSystem::join(physfs_userdir, PACKAGE_NAME); +#else + userdir = FileSystem::join(physfs_userdir, "." PACKAGE_NAME); +#endif + } - char* dir; - br_init (NULL); - dir = br_find_data_dir(datadir.c_str()); - datadir = dir; - free(dir); + if (!FileSystem::is_directory(userdir)) + { + FileSystem::mkdir(userdir); + log_info << "Created SuperTux userdir: " << userdir << std::endl; + } -#endif - if(!PHYSFS_addToSearchPath(datadir.c_str(), 1)) { - log_warning << "Couldn't add '" << datadir << "' to physfs searchpath: " << PHYSFS_getLastError() << std::endl; + if (!PHYSFS_setWriteDir(userdir.c_str())) + { + std::ostringstream msg; + msg << "Failed to use userdir directory '" + << userdir << "': " << PHYSFS_getLastError(); + throw std::runtime_error(msg.str()); } + + PHYSFS_addToSearchPath(userdir.c_str(), 0); } - //show search Path - char** searchpath = PHYSFS_getSearchPath(); - for(char** i = searchpath; *i != NULL; i++) - log_info << "[" << *i << "] is in the search path" << std::endl; - PHYSFS_freeList(searchpath); -} + void print_search_path() + { + const char* writedir = PHYSFS_getWriteDir(); + log_info << "PhysfsWritedDir: " << (writedir ? writedir : "(null)") << std::endl; + log_info << "PhysfsSearchPath:" << std::endl; + char** searchpath = PHYSFS_getSearchPath(); + for(char** i = searchpath; *i != NULL; ++i) + { + log_info << " " << *i << std::endl; + } + PHYSFS_freeList(searchpath); + } -void -Main::init_sdl() -{ - if(SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) { - std::stringstream msg; - msg << "Couldn't initialize SDL: " << SDL_GetError(); - throw std::runtime_error(msg.str()); + ~PhysfsSubsystem() + { + PHYSFS_deinit(); } - // just to be sure - atexit(SDL_Quit); -} +}; -void -Main::init_rand() +class SDLSubsystem { - g_config->random_seed = gameRandom.srand(g_config->random_seed); - - graphicsRandom.srand(0); +public: + SDLSubsystem() + { + if(SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) + { + std::stringstream msg; + msg << "Couldn't initialize SDL: " << SDL_GetError(); + throw std::runtime_error(msg.str()); + } + // just to be sure + atexit(SDL_Quit); + } - //const char *how = config->random_seed? ", user fixed.": ", from time()."; - //log_info << "Using random seed " << config->random_seed << how << std::endl; -} + ~SDLSubsystem() + { + SDL_Quit(); + } +}; void Main::init_video() { - SDL_SetWindowTitle(Renderer::instance()->get_window(), PACKAGE_NAME " " PACKAGE_VERSION); + SDL_SetWindowTitle(VideoSystem::current()->get_renderer().get_window(), PACKAGE_NAME " " PACKAGE_VERSION); const char* icon_fname = "images/engine/icons/supertux-256x256.png"; SDL_Surface* icon = IMG_Load_RW(get_physfs_SDLRWops(icon_fname), true); @@ -222,7 +267,7 @@ Main::init_video() } else { - SDL_SetWindowIcon(Renderer::instance()->get_window(), icon); + SDL_SetWindowIcon(VideoSystem::current()->get_renderer().get_window(), icon); SDL_FreeSurface(icon); } SDL_ShowCursor(0); @@ -233,24 +278,6 @@ Main::init_video() << " Area: " << g_config->aspect_size << std::endl; } -void -Main::init_audio() -{ - sound_manager = new SoundManager(); - - sound_manager->enable_sound(g_config->sound_enabled); - sound_manager->enable_music(g_config->music_enabled); -} - -void -Main::quit_audio() -{ - if(sound_manager != NULL) { - delete sound_manager; - sound_manager = NULL; - } -} - static Uint32 last_timelog_ticks = 0; static const char* last_timelog_component = 0; @@ -266,6 +293,87 @@ static inline void timelog(const char* component) last_timelog_component = component; } +void +Main::launch_game() +{ + SDLSubsystem sdl_subsystem; + ConsoleBuffer console_buffer; + + timelog("audio"); + SoundManager sound_manager; + sound_manager.enable_sound(g_config->sound_enabled); + sound_manager.enable_music(g_config->music_enabled); + + timelog("controller"); + InputManager input_manager(g_config->keyboard_config, g_config->joystick_config); + + timelog("commandline"); + + timelog("video"); + std::unique_ptr video_system = VideoSystem::create(g_config->video); + DrawingContext context(*video_system); + init_video(); + + Console console(console_buffer); + + timelog("scripting"); + scripting::Scripting scripting(g_config->enable_script_debugger); + + timelog("resources"); + TileManager tile_manager; + SpriteManager sprite_manager; + Resources resources; + + timelog("addons"); + AddonManager addon_manager("addons", g_config->addons); + + timelog(0); + + const std::unique_ptr default_savegame(new Savegame(std::string())); + + GameManager game_manager; + ScreenManager screen_manager; + + if(g_config->start_level != "") { + // we have a normal path specified at commandline, not a physfs path. + // So we simply mount that path here... + std::string dir = FileSystem::dirname(g_config->start_level); + std::string fileProtocol = "file://"; + std::string::size_type position = dir.find(fileProtocol); + if(position != std::string::npos) { + dir = dir.replace(position, fileProtocol.length(), ""); + } + log_debug << "Adding dir: " << dir << std::endl; + PHYSFS_addToSearchPath(dir.c_str(), true); + + if(g_config->start_level.size() > 4 && + g_config->start_level.compare(g_config->start_level.size() - 5, 5, ".stwm") == 0) + { + screen_manager.push_screen(std::unique_ptr( + new worldmap::WorldMap( + FileSystem::basename(g_config->start_level), *default_savegame))); + } else { + std::unique_ptr session ( + new GameSession(FileSystem::basename(g_config->start_level), *default_savegame)); + + g_config->random_seed = session->get_demo_random_seed(g_config->start_demo); + g_config->random_seed = gameRandom.srand(g_config->random_seed); + graphicsRandom.srand(0); + + if(g_config->start_demo != "") + session->play_demo(g_config->start_demo); + + if(g_config->record_demo != "") + session->record_demo(g_config->record_demo); + screen_manager.push_screen(std::move(session)); + } + } else { + screen_manager.push_screen(std::unique_ptr(new TitleScreen(*default_savegame))); + } + + screen_manager.run(context); +} + int Main::run(int argc, char** argv) { @@ -275,10 +383,6 @@ Main::run(int argc, char** argv) { CommandLineArguments args; - // Do this before pre_parse_commandline, because --help now shows the - // default user data dir. - init_physfs(argv[0]); - try { args.parse_args(argc, argv); @@ -286,23 +390,15 @@ Main::run(int argc, char** argv) } catch(const std::exception& err) { - try - { - init_config(); - args.merge_into(*g_config); - init_tinygettext(); - } - catch(const std::exception& err) - { - log_fatal << "failed to init config or tinygettext: " << err.what() << std::endl; - } - std::cout << "Error: " << err.what() << std::endl; return EXIT_FAILURE; } + PhysfsSubsystem physfs_subsystem(argv[0], args.datadir, args.userdir); + physfs_subsystem.print_search_path(); + timelog("config"); - init_config(); + ConfigSubsystem config_subsystem; args.merge_into(*g_config); timelog("tinygettext"); @@ -323,114 +419,22 @@ Main::run(int argc, char** argv) return 0; default: - // continue and start the game as usual + launch_game(); break; } - - init_sdl(); - Console::instance = new Console(); - - timelog("controller"); - g_input_manager = new InputManager(); - - timelog("commandline"); - - timelog("video"); - std::unique_ptr renderer(VideoSystem::new_renderer()); - std::unique_ptr lightmap(VideoSystem::new_lightmap()); - DrawingContext context(*renderer, *lightmap); - context_pointer = &context; - init_video(); - - timelog("audio"); - init_audio(); - - Console::instance->init_graphics(); - - timelog("scripting"); - scripting::init_squirrel(g_config->enable_script_debugger); - - timelog("resources"); - Resources::load_shared(); - - timelog("addons"); - AddonManager::get_instance().load_addons(); - - timelog(0); - - const std::unique_ptr default_world_state(new WorldState); - - GameManager game_manager; - g_screen_manager = new ScreenManager(); - - init_rand(); - - if(g_config->start_level != "") { - // we have a normal path specified at commandline, not a physfs path. - // So we simply mount that path here... - std::string dir = FileSystem::dirname(g_config->start_level); - std::string fileProtocol = "file://"; - std::string::size_type position = dir.find(fileProtocol); - if(position != std::string::npos) { - dir = dir.replace(position, fileProtocol.length(), ""); - } - log_debug << "Adding dir: " << dir << std::endl; - PHYSFS_addToSearchPath(dir.c_str(), true); - - if(g_config->start_level.size() > 4 && - g_config->start_level.compare(g_config->start_level.size() - 5, 5, ".stwm") == 0) { - g_screen_manager->push_screen(std::unique_ptr( - new worldmap::WorldMap( - FileSystem::basename(g_config->start_level), *default_world_state))); - } else { - std::unique_ptr session ( - new GameSession(FileSystem::basename(g_config->start_level), *default_world_state)); - - g_config->random_seed =session->get_demo_random_seed(g_config->start_demo); - init_rand();//initialise generator with seed from session - - if(g_config->start_demo != "") - session->play_demo(g_config->start_demo); - - if(g_config->record_demo != "") - session->record_demo(g_config->record_demo); - g_screen_manager->push_screen(std::move(session)); - } - } else { - g_screen_manager->push_screen(std::unique_ptr(new TitleScreen(*default_world_state))); - } - - g_screen_manager->run(context); - } catch(std::exception& e) { + } + catch(const std::exception& e) + { log_fatal << "Unexpected exception: " << e.what() << std::endl; result = 1; - } catch(...) { + } + catch(...) + { log_fatal << "Unexpected exception" << std::endl; result = 1; } - delete g_screen_manager; - g_screen_manager = NULL; - - Resources::unload_shared(); - quit_audio(); - - if(g_config) - g_config->save(); - delete g_config; - g_config = NULL; - delete g_input_manager; - g_input_manager = NULL; - delete Console::instance; - Console::instance = NULL; - scripting::exit_squirrel(); - delete texture_manager; - texture_manager = NULL; - SDL_Quit(); - PHYSFS_deinit(); - - delete dictionary_manager; - dictionary_manager = nullptr; + g_dictionary_manager.reset(); return result; }