int main(int argc, char *argv[]) { /* Initialization */ // Set locale. This is for forcing '.' as the decimal point. std::locale::global(std::locale("C")); // This enables printing all characters in bitmap font setlocale(LC_CTYPE, "en_US"); /* Parse command line */ // List all allowed options core::map<std::string, ValueSpec> allowed_options; allowed_options.insert("help", ValueSpec(VALUETYPE_FLAG)); allowed_options.insert("server", ValueSpec(VALUETYPE_FLAG, "Run server directly")); allowed_options.insert("config", ValueSpec(VALUETYPE_STRING, "Load configuration from specified file")); allowed_options.insert("port", ValueSpec(VALUETYPE_STRING)); allowed_options.insert("address", ValueSpec(VALUETYPE_STRING)); allowed_options.insert("random-input", ValueSpec(VALUETYPE_FLAG)); allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG)); allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG)); allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING)); #ifdef _WIN32 allowed_options.insert("dstream-on-stderr", ValueSpec(VALUETYPE_FLAG)); #endif allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG)); Settings cmd_args; bool ret = cmd_args.parseCommandLine(argc, argv, allowed_options); if(ret == false || cmd_args.getFlag("help")) { dstream<<"Allowed options:"<<std::endl; for(core::map<std::string, ValueSpec>::Iterator i = allowed_options.getIterator(); i.atEnd() == false; i++) { dstream<<" --"<<i.getNode()->getKey(); if(i.getNode()->getValue().type == VALUETYPE_FLAG) { } else { dstream<<" <value>"; } dstream<<std::endl; if(i.getNode()->getValue().help != NULL) { dstream<<" "<<i.getNode()->getValue().help <<std::endl; } } return cmd_args.getFlag("help") ? 0 : 1; } /* Low-level initialization */ bool disable_stderr = false; #ifdef _WIN32 if(cmd_args.getFlag("dstream-on-stderr") == false) disable_stderr = true; #endif porting::signal_handler_init(); bool &kill = *porting::signal_handler_killstatus(); // Initialize porting::path_data and porting::path_userdata porting::initializePaths(); // Create user data directory fs::CreateDir(porting::path_userdata); setlocale(LC_ALL, ""); bindtextdomain("minetest-c55", (porting::path_userdata+"/locale").c_str()); textdomain("minetest-c55"); // Initialize debug streams #ifdef RUN_IN_PLACE std::string debugfile = DEBUGFILE; #else std::string debugfile = porting::path_userdata+"/"+DEBUGFILE; #endif debugstreams_init(disable_stderr, debugfile.c_str()); // Initialize debug stacks debug_stacks_init(); DSTACK(__FUNCTION_NAME); // Init material properties table //initializeMaterialProperties(); // Debug handler BEGIN_DEBUG_EXCEPTION_HANDLER // Print startup message dstream<<DTIME<<"minetest-c55" " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST <<", "<<BUILD_INFO <<std::endl; /* Basic initialization */ // Initialize default settings set_default_settings(); // Initialize sockets sockets_init(); atexit(sockets_cleanup); /* Read config file */ // Path of configuration file in use std::string configpath = ""; if(cmd_args.exists("config")) { bool r = g_settings.readConfigFile(cmd_args.get("config").c_str()); if(r == false) { dstream<<"Could not read configuration from \"" <<cmd_args.get("config")<<"\""<<std::endl; return 1; } configpath = cmd_args.get("config"); } else { core::array<std::string> filenames; filenames.push_back(porting::path_userdata + "/minetest.conf"); #ifdef RUN_IN_PLACE filenames.push_back(porting::path_userdata + "/../minetest.conf"); #endif for(u32 i=0; i<filenames.size(); i++) { bool r = g_settings.readConfigFile(filenames[i].c_str()); if(r) { configpath = filenames[i]; break; } } // If no path found, use the first one (menu creates the file) if(configpath == "") configpath = filenames[0]; } // Initialize random seed srand(time(0)); mysrand(time(0)); /* Pre-initialize some stuff with a dummy irrlicht wrapper. These are needed for unit tests at least. */ // Initial call with g_texturesource not set. init_mapnode(); /* Run unit tests */ if((ENABLE_TESTS && cmd_args.getFlag("disable-unittests") == false) || cmd_args.getFlag("enable-unittests") == true) { run_tests(); } /*for(s16 y=-100; y<100; y++) for(s16 x=-100; x<100; x++) { std::cout<<noise2d_gradient((double)x/10,(double)y/10, 32415)<<std::endl; } return 0;*/ /* Game parameters */ // Port u16 port = 30000; if(cmd_args.exists("port")) port = cmd_args.getU16("port"); else if(g_settings.exists("port")) port = g_settings.getU16("port"); if(port == 0) port = 30000; // Map directory std::string map_dir = porting::path_userdata+"/world"; if(cmd_args.exists("map-dir")) map_dir = cmd_args.get("map-dir"); else if(g_settings.exists("map-dir")) map_dir = g_settings.get("map-dir"); // Run dedicated server if asked to if(cmd_args.getFlag("server")) { DSTACK("Dedicated server branch"); // Create time getter g_timegetter = new SimpleTimeGetter(); // Create server Server server(map_dir.c_str()); server.start(port); // Run server dedicated_server_loop(server, kill); return 0; } /* More parameters */ // Address to connect to std::string address = ""; if(cmd_args.exists("address")) { address = cmd_args.get("address"); } else { address = g_settings.get("address"); } std::string playername = g_settings.get("name"); /* Device initialization */ // Resolution selection bool fullscreen = false; u16 screenW = g_settings.getU16("screenW"); u16 screenH = g_settings.getU16("screenH"); // Determine driver video::E_DRIVER_TYPE driverType; std::string driverstring = g_settings.get("video_driver"); if(driverstring == "null") driverType = video::EDT_NULL; else if(driverstring == "software") driverType = video::EDT_SOFTWARE; else if(driverstring == "burningsvideo") driverType = video::EDT_BURNINGSVIDEO; else if(driverstring == "direct3d8") driverType = video::EDT_DIRECT3D8; else if(driverstring == "direct3d9") driverType = video::EDT_DIRECT3D9; else if(driverstring == "opengl") driverType = video::EDT_OPENGL; else { dstream<<"WARNING: Invalid video_driver specified; defaulting " "to opengl"<<std::endl; driverType = video::EDT_OPENGL; } /* Create device and exit if creation failed */ MyEventReceiver receiver; IrrlichtDevice *device; device = createDevice(driverType, core::dimension2d<u32>(screenW, screenH), 16, fullscreen, false, false, &receiver); if (device == 0) return 1; // could not create selected driver. // Set device in game parameters device = device; // Set the window caption device->setWindowCaption(L"Minetest [Main Menu]"); // Create time getter g_timegetter = new IrrlichtTimeGetter(device); // Create game callback for menus g_gamecallback = new MainGameCallback(device); // Create texture source g_texturesource = new TextureSource(device); /* Speed tests (done after irrlicht is loaded to get timer) */ if(cmd_args.getFlag("speedtests")) { dstream<<"Running speed tests"<<std::endl; SpeedTests(); return 0; } device->setResizable(true); bool random_input = g_settings.getBool("random_input") || cmd_args.getFlag("random-input"); InputHandler *input = NULL; if(random_input) input = new RandomInputHandler(); else input = new RealInputHandler(device, &receiver); /* Continue initialization */ //video::IVideoDriver* driver = device->getVideoDriver(); /* This changes the minimum allowed number of vertices in a VBO. Default is 500. */ //driver->setMinHardwareBufferVertexCount(50); scene::ISceneManager* smgr = device->getSceneManager(); guienv = device->getGUIEnvironment(); gui::IGUISkin* skin = guienv->getSkin(); gui::IGUIFont* font = guienv->getFont(getTexturePath("fontlucida.png").c_str()); if(font) skin->setFont(font); else dstream<<"WARNING: Font file was not found." " Using default font."<<std::endl; // If font was not found, this will get us one font = skin->getFont(); assert(font); u32 text_height = font->getDimension(L"Hello, world!").Height; dstream<<"text_height="<<text_height<<std::endl; //skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,0,0,0)); skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,255,255,255)); //skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(0,0,0,0)); //skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(0,0,0,0)); skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255,0,0,0)); skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255,0,0,0)); /* Preload some textures and stuff */ init_mapnode(); // Second call with g_texturesource set init_mineral(); /* GUI stuff */ /* If an error occurs, this is set to something and the menu-game loop is restarted. It is then displayed before the menu. */ std::wstring error_message = L""; // The password entered during the menu screen, std::string password; /* Menu-game loop */ while(device->run() && kill == false) { // This is used for catching disconnects try { /* Clear everything from the GUIEnvironment */ guienv->clear(); /* We need some kind of a root node to be able to add custom gui elements directly on the screen. Otherwise they won't be automatically drawn. */ guiroot = guienv->addStaticText(L"", core::rect<s32>(0, 0, 10000, 10000)); /* Out-of-game menu loop. Loop quits when menu returns proper parameters. */ while(kill == false) { // Cursor can be non-visible when coming from the game device->getCursorControl()->setVisible(true); // Some stuff are left to scene manager when coming from the game // (map at least?) smgr->clear(); // Reset or hide the debug gui texts /*guitext->setText(L"Minetest-c55"); guitext2->setVisible(false); guitext_info->setVisible(false); guitext_chat->setVisible(false);*/ // Initialize menu data MainMenuData menudata; menudata.address = narrow_to_wide(address); menudata.name = narrow_to_wide(playername); menudata.port = narrow_to_wide(itos(port)); menudata.fancy_trees = g_settings.getBool("new_style_leaves"); menudata.smooth_lighting = g_settings.getBool("smooth_lighting"); menudata.creative_mode = g_settings.getBool("creative_mode"); menudata.enable_damage = g_settings.getBool("enable_damage"); GUIMainMenu *menu = new GUIMainMenu(guienv, guiroot, -1, &g_menumgr, &menudata, g_gamecallback); menu->allowFocusRemoval(true); if(error_message != L"") { dstream<<"WARNING: error_message = " <<wide_to_narrow(error_message)<<std::endl; GUIMessageMenu *menu2 = new GUIMessageMenu(guienv, guiroot, -1, &g_menumgr, error_message.c_str()); menu2->drop(); error_message = L""; } video::IVideoDriver* driver = device->getVideoDriver(); dstream<<"Created main menu"<<std::endl; while(device->run() && kill == false) { if(menu->getStatus() == true) break; //driver->beginScene(true, true, video::SColor(255,0,0,0)); driver->beginScene(true, true, video::SColor(255,128,128,128)); drawMenuBackground(driver); guienv->drawAll(); driver->endScene(); // On some computers framerate doesn't seem to be // automatically limited sleep_ms(25); } // Break out of menu-game loop to shut down cleanly if(device->run() == false || kill == true) break; dstream<<"Dropping main menu"<<std::endl; menu->drop(); // Delete map if requested if(menudata.delete_map) { bool r = fs::RecursiveDeleteContent(map_dir); if(r == false) error_message = L"Delete failed"; continue; } playername = wide_to_narrow(menudata.name); password = translatePassword(playername, menudata.password); address = wide_to_narrow(menudata.address); int newport = stoi(wide_to_narrow(menudata.port)); if(newport != 0) port = newport; g_settings.set("new_style_leaves", itos(menudata.fancy_trees)); g_settings.set("smooth_lighting", itos(menudata.smooth_lighting)); g_settings.set("creative_mode", itos(menudata.creative_mode)); g_settings.set("enable_damage", itos(menudata.enable_damage)); // NOTE: These are now checked server side; no need to do it // here, so let's not do it here. /*// Check for valid parameters, restart menu if invalid. if(playername == "") { error_message = L"Name required."; continue; } // Check that name has only valid chars if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false) { error_message = L"Characters allowed: " +narrow_to_wide(PLAYERNAME_ALLOWED_CHARS); continue; }*/ // Save settings g_settings.set("name", playername); g_settings.set("address", address); g_settings.set("port", itos(port)); // Update configuration file if(configpath != "") g_settings.updateConfigFile(configpath.c_str()); // Continue to game break; } // Break out of menu-game loop to shut down cleanly if(device->run() == false) break; // Initialize mapnode again to enable changed graphics settings init_mapnode(); /* Run game */ the_game( kill, random_input, input, device, font, map_dir, playername, password, address, port, error_message ); } //try catch(con::PeerNotFoundException &e) { dstream<<DTIME<<"Connection error (timed out?)"<<std::endl; error_message = L"Connection error (timed out?)"; } catch(SocketException &e) { dstream<<DTIME<<"Socket error (port already in use?)"<<std::endl; error_message = L"Socket error (port already in use?)"; } #ifdef NDEBUG catch(std::exception &e) { std::string narrow_message = "Some exception, what()=\""; narrow_message += e.what(); narrow_message += "\""; dstream<<DTIME<<narrow_message<<std::endl; error_message = narrow_to_wide(narrow_message); } #endif } // Menu-game loop delete input; /* In the end, delete the Irrlicht device. */ device->drop(); END_DEBUG_EXCEPTION_HANDLER debugstreams_deinit(); return 0; }
int main(int argc, char *argv[]) { /* Initialization */ log_add_output_maxlev(&main_stderr_log_out, LMT_ACTION); log_add_output_all_levs(&main_dstream_no_stderr_log_out); log_register_thread("main"); // Set locale. This is for forcing '.' as the decimal point. std::locale::global(std::locale("C")); // This enables printing all characters in bitmap font setlocale(LC_CTYPE, "en_US"); /* Low-level initialization */ bool disable_stderr = false; #ifdef _WIN32 disable_stderr = true; #endif porting::signal_handler_init(); bool &kill = *porting::signal_handler_killstatus(); // Initialize porting::path_data and porting::path_userdata porting::initializePaths(); // Create user data directory fs::CreateDir(porting::path_userdata); // Initialize debug streams #ifdef RUN_IN_PLACE std::string debugfile = DEBUGFILE; #else std::string debugfile = porting::path_userdata+DIR_DELIM+DEBUGFILE; #endif debugstreams_init(disable_stderr, debugfile.c_str()); // Initialize debug stacks debug_stacks_init(); DSTACK(__FUNCTION_NAME); // Init material properties table //initializeMaterialProperties(); // Debug handler BEGIN_DEBUG_EXCEPTION_HANDLER // Print startup message actionstream<<PROJECT_NAME<< " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST <<", "<<BUILD_INFO <<std::endl; try { /* Parse command line */ // List all allowed options core::map<std::string, ValueSpec> allowed_options; allowed_options.insert("help", ValueSpec(VALUETYPE_FLAG)); allowed_options.insert("config", ValueSpec(VALUETYPE_STRING, "Load configuration from specified file")); allowed_options.insert("port", ValueSpec(VALUETYPE_STRING)); allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG)); allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG)); allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING)); allowed_options.insert("info-on-stderr", ValueSpec(VALUETYPE_FLAG)); Settings cmd_args; bool ret = cmd_args.parseCommandLine(argc, argv, allowed_options); if(ret == false || cmd_args.getFlag("help")) { dstream<<"Allowed options:"<<std::endl; for(core::map<std::string, ValueSpec>::Iterator i = allowed_options.getIterator(); i.atEnd() == false; i++) { dstream<<" --"<<i.getNode()->getKey(); if(i.getNode()->getValue().type == VALUETYPE_FLAG) { } else { dstream<<" <value>"; } dstream<<std::endl; if(i.getNode()->getValue().help != NULL) { dstream<<" "<<i.getNode()->getValue().help <<std::endl; } } return cmd_args.getFlag("help") ? 0 : 1; } if(cmd_args.getFlag("info-on-stderr")) log_add_output(&main_stderr_log_out, LMT_INFO); /* Basic initialization */ // Initialize default settings set_default_settings(g_settings); // Initialize sockets sockets_init(); atexit(sockets_cleanup); /* Read config file */ // Path of configuration file in use std::string configpath = ""; if(cmd_args.exists("config")) { bool r = g_settings->readConfigFile(cmd_args.get("config").c_str()); if(r == false) { errorstream<<"Could not read configuration from \"" <<cmd_args.get("config")<<"\""<<std::endl; return 1; } configpath = cmd_args.get("config"); } else { core::array<std::string> filenames; filenames.push_back(porting::path_userdata + DIR_DELIM + "minetest.conf"); #ifdef RUN_IN_PLACE filenames.push_back(porting::path_userdata + DIR_DELIM + ".." + DIR_DELIM + "minetest.conf"); #endif for(u32 i=0; i<filenames.size(); i++) { bool r = g_settings->readConfigFile(filenames[i].c_str()); if(r) { configpath = filenames[i]; break; } } } // Initialize random seed srand(time(0)); mysrand(time(0)); // Initialize stuff init_mapnode(); init_mineral(); /* Run unit tests */ if((ENABLE_TESTS && cmd_args.getFlag("disable-unittests") == false) || cmd_args.getFlag("enable-unittests") == true) { run_tests(); } /* Check parameters */ std::cout<<std::endl<<std::endl; std::cout <<" .__ __ __ "<<std::endl <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl <<std::endl; std::cout<<std::endl; // Port? u16 port = 30000; if(cmd_args.exists("port") && cmd_args.getU16("port") != 0) { port = cmd_args.getU16("port"); } else if(g_settings->exists("port") && g_settings->getU16("port") != 0) { port = g_settings->getU16("port"); } else { dstream<<"Please specify port (in config or on command line)" <<std::endl; } // Figure out path to map std::string map_dir = porting::path_userdata+DIR_DELIM+"world"; if(cmd_args.exists("map-dir")) map_dir = cmd_args.get("map-dir"); else if(g_settings->exists("map-dir")) map_dir = g_settings->get("map-dir"); // Create server Server server(map_dir.c_str(), configpath); server.start(port); // Run server dedicated_server_loop(server, kill); } //try catch(con::PeerNotFoundException &e) { errorstream<<"Connection timed out."<<std::endl; } END_DEBUG_EXCEPTION_HANDLER(errorstream) debugstreams_deinit(); return 0; }