]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/main.cpp
Tune "Connecting to server" and "Waiting content" screens
[dragonfireclient.git] / src / main.cpp
index 80daf744937f763088606081dd47ae6a8502e511..10e01be2ad006a6d0fd2f92263839d4adc8a91d7 100644 (file)
@@ -54,24 +54,6 @@ A list of "active blocks" in which stuff happens. (+=done)
                + This was left to be done by the old system and it sends only the
                  nearest ones.
 
-Vim conversion regexpes for moving to extended content type storage:
-%s/\(\.\|->\)d \([!=]=\)/\1getContent() \2/g
-%s/content_features(\([^.]*\)\.d)/content_features(\1)/g
-%s/\(\.\|->\)d = \([^;]*\);/\1setContent(\2);/g
-%s/\(getNodeNoExNoEmerge([^)]*)\)\.d/\1.getContent()/g
-%s/\(getNodeNoExNoEmerge(.*)\)\.d/\1.getContent()/g
-%s/\.d;/.getContent();/g
-%s/\(content_liquid\|content_flowing_liquid\|make_liquid_flowing\|content_pointable\)(\([^.]*\).d)/\1(\2.getContent())/g
-Other things to note:
-- node.d = node.param0 (only in raw serialization; use getContent() otherwise)
-- node.param = node.param1
-- node.dir = node.param2
-- content_walkable(node.d) etc should be changed to
-  content_features(node).walkable etc
-- Also check for lines that store the result of getContent to a 8-bit
-  variable and fix them (result of getContent() must be stored in
-  content_t, which is 16-bit)
-
 NOTE: Seeds in 1260:6c77e7dbfd29:
 5721858502589302589:
        Spawns you on a small sand island with a surface dungeon
@@ -334,11 +316,6 @@ TODO: Add a long step function to objects that is called with the time
 Map:
 ----
 
-TODO: Mineral and ground material properties
-      - This way mineral ground toughness can be calculated with just
-           some formula, as well as tool strengths. Sounds too.
-         - There are TODOs in appropriate files: material.h, content_mapnode.h
-
 TODO: Flowing water to actually contain flow direction information
       - There is a space for this - it just has to be implemented.
 
@@ -356,8 +333,6 @@ TODO: Block cube placement around player's head
 TODO: Protocol version field
 TODO: Think about using same bits for material for fences and doors, for
          example
-TODO: Move mineral to param2, increment map serialization version, add
-      conversion
 
 SUGG: Restart irrlicht completely when coming back to main menu from game.
        - This gets rid of everything that is stored in irrlicht's caches.
@@ -365,11 +340,6 @@ SUGG: Restart irrlicht completely when coming back to main menu from game.
 
 TODO: Merge bahamada's audio stuff (clean patch available)
 
-TODO: Move content_features to mapnode_content_features.{h,cpp} or so
-
-TODO: Fix item use() stuff; dropping a stack of cooked rats and eating
-      it gives 3 hearts and consumes all the rats.
-
 Making it more portable:
 ------------------------
  
@@ -390,11 +360,11 @@ Doing currently:
 */
 
 #ifdef NDEBUG
-       #ifdef _WIN32
+       /*#ifdef _WIN32
                #pragma message ("Disabling unit tests")
        #else
                #warning "Disabling unit tests"
-       #endif
+       #endif*/
        // Disable unit tests
        #define ENABLE_TESTS 0
 #else
@@ -403,13 +373,14 @@ Doing currently:
 #endif
 
 #ifdef _MSC_VER
+#ifndef SERVER // Dedicated server isn't linked with Irrlicht
        #pragma comment(lib, "Irrlicht.lib")
-       //#pragma comment(lib, "jthread.lib")
-       #pragma comment(lib, "zlibwapi.lib")
-       #pragma comment(lib, "Shell32.lib")
        // This would get rid of the console window
        //#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
 #endif
+       #pragma comment(lib, "zlibwapi.lib")
+       #pragma comment(lib, "Shell32.lib")
+#endif
 
 #include "irrlicht.h" // createDevice
 
@@ -429,19 +400,16 @@ Doing currently:
 #include "filesys.h"
 #include "config.h"
 #include "guiMainMenu.h"
-#include "mineral.h"
-#include "materials.h"
 #include "game.h"
 #include "keycode.h"
 #include "tile.h"
+#include "chat.h"
 #include "defaultsettings.h"
 #include "gettext.h"
 #include "settings.h"
 #include "profiler.h"
 #include "log.h"
-
-// This makes textures
-ITextureSource *g_texturesource = NULL;
+#include "mods.h"
 
 /*
        Settings.
@@ -455,13 +423,30 @@ Profiler main_profiler;
 Profiler *g_profiler = &main_profiler;
 
 /*
-       Random stuff
+       Debug streams
 */
 
+// Connection
+std::ostream *dout_con_ptr = &dummyout;
+std::ostream *derr_con_ptr = &verbosestream;
+//std::ostream *dout_con_ptr = &infostream;
+//std::ostream *derr_con_ptr = &errorstream;
+
+// Server
+std::ostream *dout_server_ptr = &infostream;
+std::ostream *derr_server_ptr = &errorstream;
+
+// Client
+std::ostream *dout_client_ptr = &infostream;
+std::ostream *derr_client_ptr = &errorstream;
+
+#ifndef SERVER
 /*
-       mainmenumanager.h
+       Random stuff
 */
 
+/* mainmenumanager.h */
+
 gui::IGUIEnvironment* guienv = NULL;
 gui::IGUIStaticText *guiroot = NULL;
 MainMenuManager g_menumgr;
@@ -473,26 +458,21 @@ bool noMenuActive()
 
 // Passed to menus to allow disconnecting and exiting
 MainGameCallback *g_gamecallback = NULL;
+#endif
 
 /*
-       Debug streams
+       gettime.h implementation
 */
 
-// Connection
-std::ostream *dout_con_ptr = &dummyout;
-std::ostream *derr_con_ptr = &verbosestream;
-
-// Server
-std::ostream *dout_server_ptr = &infostream;
-std::ostream *derr_server_ptr = &errorstream;
+#ifdef SERVER
 
-// Client
-std::ostream *dout_client_ptr = &infostream;
-std::ostream *derr_client_ptr = &errorstream;
+u32 getTimeMs()
+{
+       /* Use imprecise system calls directly (from porting.h) */
+       return porting::getTimeMs();
+}
 
-/*
-       gettime.h implementation
-*/
+#else
 
 // A small helper class
 class TimeGetter
@@ -538,6 +518,30 @@ u32 getTimeMs()
        return g_timegetter->getTime();
 }
 
+#endif
+
+class StderrLogOutput: public ILogOutput
+{
+public:
+       /* line: Full line with timestamp, level and thread */
+       void printLog(const std::string &line)
+       {
+               std::cerr<<line<<std::endl;
+       }
+} main_stderr_log_out;
+
+class DstreamNoStderrLogOutput: public ILogOutput
+{
+public:
+       /* line: Full line with timestamp, level and thread */
+       void printLog(const std::string &line)
+       {
+               dstream_no_stderr<<line<<std::endl;
+       }
+} main_dstream_no_stderr_log_out;
+
+#ifndef SERVER
+
 /*
        Event handler for Irrlicht
 
@@ -929,6 +933,55 @@ class RandomInputHandler : public InputHandler
        bool rightreleased;
 };
 
+void drawMenuBackground(video::IVideoDriver* driver)
+{
+       core::dimension2d<u32> screensize = driver->getScreenSize();
+               
+       video::ITexture *bgtexture =
+                       driver->getTexture(getTexturePath("menubg.png").c_str());
+       if(bgtexture)
+       {
+               s32 scaledsize = 128;
+               
+               // The important difference between destsize and screensize is
+               // that destsize is rounded to whole scaled pixels.
+               // These formulas use component-wise multiplication and division of v2u32.
+               v2u32 texturesize = bgtexture->getSize();
+               v2u32 sourcesize = texturesize * screensize / scaledsize + v2u32(1,1);
+               v2u32 destsize = scaledsize * sourcesize / texturesize;
+               
+               // Default texture wrapping mode in Irrlicht is ETC_REPEAT.
+               driver->draw2DImage(bgtexture,
+                       core::rect<s32>(0, 0, destsize.X, destsize.Y),
+                       core::rect<s32>(0, 0, sourcesize.X, sourcesize.Y),
+                       NULL, NULL, true);
+       }
+       
+       video::ITexture *logotexture =
+                       driver->getTexture(getTexturePath("menulogo.png").c_str());
+       if(logotexture)
+       {
+               v2s32 logosize(logotexture->getOriginalSize().Width,
+                               logotexture->getOriginalSize().Height);
+               logosize *= 4;
+
+               video::SColor bgcolor(255,50,50,50);
+               core::rect<s32> bgrect(0, screensize.Height-logosize.Y-20,
+                               screensize.Width, screensize.Height);
+               driver->draw2DRectangle(bgcolor, bgrect, NULL);
+
+               core::rect<s32> rect(0,0,logosize.X,logosize.Y);
+               rect += v2s32(screensize.Width/2,screensize.Height-10-logosize.Y);
+               rect -= v2s32(logosize.X/2, 0);
+               driver->draw2DImage(logotexture, rect,
+                       core::rect<s32>(core::position2d<s32>(0,0),
+                       core::dimension2di(logotexture->getSize())),
+                       NULL, NULL, true);
+       }
+}
+
+#endif
+
 // These are defined global so that they're not optimized too much.
 // Can't change them to volatile.
 s16 temp16;
@@ -941,7 +994,7 @@ std::string tempstring2;
 void SpeedTests()
 {
        {
-               dstream<<"The following test should take around 20ms."<<std::endl;
+               infostream<<"The following test should take around 20ms."<<std::endl;
                TimeTaker timer("Testing std::string speed");
                const u32 jj = 10000;
                for(u32 j=0; j<jj; j++)
@@ -960,7 +1013,7 @@ void SpeedTests()
                }
        }
        
-       dstream<<"All of the following tests should take around 100ms each."
+       infostream<<"All of the following tests should take around 100ms each."
                        <<std::endl;
 
        {
@@ -1003,7 +1056,7 @@ void SpeedTests()
        }
 
        {
-               dstream<<"Around 5000/ms should do well here."<<std::endl;
+               infostream<<"Around 5000/ms should do well here."<<std::endl;
                TimeTaker timer("Testing mutex speed");
                
                JMutex m;
@@ -1022,85 +1075,18 @@ void SpeedTests()
 
                u32 dtime = timer.stop();
                u32 per_ms = n / dtime;
-               dstream<<"Done. "<<dtime<<"ms, "
+               infostream<<"Done. "<<dtime<<"ms, "
                                <<per_ms<<"/ms"<<std::endl;
        }
 }
 
-void drawMenuBackground(video::IVideoDriver* driver)
-{
-       core::dimension2d<u32> screensize = driver->getScreenSize();
-               
-       video::ITexture *bgtexture =
-                       driver->getTexture(getTexturePath("mud.png").c_str());
-       if(bgtexture)
-       {
-               s32 texturesize = 128;
-               s32 tiled_y = screensize.Height / texturesize + 1;
-               s32 tiled_x = screensize.Width / texturesize + 1;
-               
-               for(s32 y=0; y<tiled_y; y++)
-               for(s32 x=0; x<tiled_x; x++)
-               {
-                       core::rect<s32> rect(0,0,texturesize,texturesize);
-                       rect += v2s32(x*texturesize, y*texturesize);
-                       driver->draw2DImage(bgtexture, rect,
-                               core::rect<s32>(core::position2d<s32>(0,0),
-                               core::dimension2di(bgtexture->getSize())),
-                               NULL, NULL, true);
-               }
-       }
-       
-       video::ITexture *logotexture =
-                       driver->getTexture(getTexturePath("menulogo.png").c_str());
-       if(logotexture)
-       {
-               v2s32 logosize(logotexture->getOriginalSize().Width,
-                               logotexture->getOriginalSize().Height);
-               logosize *= 4;
-
-               video::SColor bgcolor(255,50,50,50);
-               core::rect<s32> bgrect(0, screensize.Height-logosize.Y-20,
-                               screensize.Width, screensize.Height);
-               driver->draw2DRectangle(bgcolor, bgrect, NULL);
-
-               core::rect<s32> rect(0,0,logosize.X,logosize.Y);
-               rect += v2s32(screensize.Width/2,screensize.Height-10-logosize.Y);
-               rect -= v2s32(logosize.X/2, 0);
-               driver->draw2DImage(logotexture, rect,
-                       core::rect<s32>(core::position2d<s32>(0,0),
-                       core::dimension2di(logotexture->getSize())),
-                       NULL, NULL, true);
-       }
-}
-
-class DstreamLogOutput: public ILogOutput
-{
-public:
-       /* line: Full line with timestamp, level and thread */
-       void printLog(const std::string &line)
-       {
-               dstream<<line<<std::endl;
-       }
-} main_dstream_log_out;
-
-class DstreamNoStderrLogOutput: public ILogOutput
-{
-public:
-       /* line: Full line with timestamp, level and thread */
-       void printLog(const std::string &line)
-       {
-               dstream_no_stderr<<line<<std::endl;
-       }
-} main_dstream_no_stderr_log_out;
-
 int main(int argc, char *argv[])
 {
        /*
                Initialization
        */
 
-       log_add_output_maxlev(&main_dstream_log_out, LMT_ACTION);
+       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");
@@ -1116,22 +1102,30 @@ int main(int argc, char *argv[])
        
        // 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("help", ValueSpec(VALUETYPE_FLAG,
+                       "Show allowed options"));
        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));
+       allowed_options.insert("port", ValueSpec(VALUETYPE_STRING,
+                       "Set network port (UDP) to use"));
+       allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG,
+                       "Disable unit tests"));
+       allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG,
+                       "Enable unit tests"));
+       allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING,
+                       "Map directory (where everything in the world is stored)"));
+       allowed_options.insert("info-on-stderr", ValueSpec(VALUETYPE_FLAG,
+                       "Print debug information to console"));
+#ifndef SERVER
+       allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG,
+                       "Run speed tests"));
+       allowed_options.insert("address", ValueSpec(VALUETYPE_STRING,
+                       "Address to connect to"));
+       allowed_options.insert("random-input", ValueSpec(VALUETYPE_FLAG,
+                       "Enable random user input, for testing"));
+       allowed_options.insert("server", ValueSpec(VALUETYPE_FLAG,
+                       "Run server directly"));
 #endif
-       allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG));
-       allowed_options.insert("info-on-stderr", ValueSpec(VALUETYPE_FLAG));
 
        Settings cmd_args;
        
@@ -1168,32 +1162,26 @@ int main(int argc, char *argv[])
                Low-level initialization
        */
 
-       bool disable_stderr = false;
-#ifdef _WIN32
-       if(cmd_args.getFlag("dstream-on-stderr") == false)
-               disable_stderr = true;
-#endif
-       
-       if(cmd_args.getFlag("info-on-stderr"))
-               log_add_output(&main_dstream_log_out, LMT_INFO);
+       if(cmd_args.getFlag("info-on-stderr") || cmd_args.getFlag("speedtests"))
+               log_add_output(&main_stderr_log_out, LMT_INFO);
 
        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);
+       fs::CreateDir(porting::path_user);
 
-       init_gettext((porting::path_data+DIR_DELIM+".."+DIR_DELIM+"locale").c_str());
+       init_gettext((porting::path_share+DIR_DELIM+".."+DIR_DELIM+"locale").c_str());
        
        // Initialize debug streams
 #ifdef RUN_IN_PLACE
        std::string debugfile = DEBUGFILE;
 #else
-       std::string debugfile = porting::path_userdata+DIR_DELIM+DEBUGFILE;
+       std::string debugfile = porting::path_user+DIR_DELIM+DEBUGFILE;
 #endif
+       bool disable_stderr = false;
        debugstreams_init(disable_stderr, debugfile.c_str());
        // Initialize debug stacks
        debug_stacks_init();
@@ -1244,11 +1232,16 @@ int main(int argc, char *argv[])
        else
        {
                core::array<std::string> filenames;
-               filenames.push_back(porting::path_userdata +
+               filenames.push_back(porting::path_user +
                                DIR_DELIM + "minetest.conf");
-#ifdef RUN_IN_PLACE
-               filenames.push_back(porting::path_userdata +
+               // Legacy configuration file location
+               filenames.push_back(porting::path_user +
                                DIR_DELIM + ".." + DIR_DELIM + "minetest.conf");
+#ifdef RUN_IN_PLACE
+               // Try also from a lower level (to aid having the same configuration
+               // for many RUN_IN_PLACE installs)
+               filenames.push_back(porting::path_user +
+                               DIR_DELIM + ".." + DIR_DELIM + ".." + DIR_DELIM + "minetest.conf");
 #endif
 
                for(u32 i=0; i<filenames.size(); i++)
@@ -1270,15 +1263,6 @@ int main(int argc, char *argv[])
        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
        */
@@ -1289,13 +1273,6 @@ int main(int argc, char *argv[])
                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
        */
@@ -1310,30 +1287,59 @@ int main(int argc, char *argv[])
                port = 30000;
        
        // Map directory
-       std::string map_dir = porting::path_userdata+DIR_DELIM+"world";
+       std::string map_dir = porting::path_user + DIR_DELIM + "server" + DIR_DELIM + "worlds" + 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");
-       
-       // Run dedicated server if asked to
-       if(cmd_args.getFlag("server"))
+       else{
+               // No map-dir option was specified.
+               // Check if the world is found from the default directory, and if
+               // not, see if the legacy world directory exists.
+               std::string legacy_map_dir = porting::path_user+DIR_DELIM+".."+DIR_DELIM+"world";
+               if(!fs::PathExists(map_dir) && fs::PathExists(legacy_map_dir)){
+                       errorstream<<"Warning: Using legacy world directory \""
+                                       <<legacy_map_dir<<"\""<<std::endl;
+                       map_dir = legacy_map_dir;
+               }
+       }
+
+       // Run dedicated server if asked to or no other option
+#ifdef SERVER
+       bool run_dedicated_server = true;
+#else
+       bool run_dedicated_server = cmd_args.getFlag("server");
+#endif
+       if(run_dedicated_server)
        {
                DSTACK("Dedicated server branch");
 
-               // Create time getter
+               // Create time getter if built with Irrlicht
+#ifndef SERVER
                g_timegetter = new SimpleTimeGetter();
+#endif
                
                // Create server
-               Server server(map_dir.c_str(), configpath);
+               Server server(map_dir, configpath, "mesetint");
                server.start(port);
                
+               // ASCII art for the win!
+               actionstream
+               <<"        .__               __                   __   "<<std::endl
+               <<"  _____ |__| ____   _____/  |_  ____   _______/  |_ "<<std::endl
+               <<" /     \\|  |/    \\_/ __ \\   __\\/ __ \\ /  ___/\\   __\\"<<std::endl
+               <<"|  Y Y  \\  |   |  \\  ___/|  | \\  ___/ \\___ \\  |  |  "<<std::endl
+               <<"|__|_|  /__|___|  /\\___  >__|  \\___  >____  > |__|  "<<std::endl
+               <<"      \\/        \\/     \\/          \\/     \\/        "<<std::endl;
+               actionstream<<"Listening at port "<<port<<"."<<std::endl;
+       
                // Run server
                dedicated_server_loop(server, kill);
 
                return 0;
        }
 
+#ifndef SERVER // Exclude from dedicated server build
 
        /*
                More parameters
@@ -1402,6 +1408,21 @@ int main(int argc, char *argv[])
        if (device == 0)
                return 1; // could not create selected driver.
        
+       /*
+               Continue initialization
+       */
+
+       video::IVideoDriver* driver = device->getVideoDriver();
+
+       // Disable mipmaps (because some of them look ugly)
+       driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
+
+       /*
+               This changes the minimum allowed number of vertices in a VBO.
+               Default is 500.
+       */
+       //driver->setMinHardwareBufferVertexCount(50);
+
        // Set the window caption
        device->setWindowCaption(L"Minetest [Main Menu]");
        
@@ -1411,9 +1432,6 @@ int main(int argc, char *argv[])
        // 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)
        */
@@ -1434,18 +1452,6 @@ int main(int argc, char *argv[])
        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();
@@ -1470,17 +1476,12 @@ int main(int argc, char *argv[])
        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
        */
 
+       ChatBackend chat_backend;
+
        /*
                If an error occurs, this is set to something and the
                menu-game loop is restarted. It is then displayed before
@@ -1539,6 +1540,8 @@ int main(int argc, char *argv[])
                                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.clouds_3d = g_settings->getBool("enable_3d_clouds");
+                               menudata.opaque_water = g_settings->getBool("opaque_water");
                                menudata.creative_mode = g_settings->getBool("creative_mode");
                                menudata.enable_damage = g_settings->getBool("enable_damage");
 
@@ -1611,6 +1614,8 @@ int main(int argc, char *argv[])
                                        port = newport;
                                g_settings->set("new_style_leaves", itos(menudata.fancy_trees));
                                g_settings->set("smooth_lighting", itos(menudata.smooth_lighting));
+                               g_settings->set("enable_3d_clouds", itos(menudata.clouds_3d));
+                               g_settings->set("opaque_water", itos(menudata.opaque_water));
                                g_settings->set("creative_mode", itos(menudata.creative_mode));
                                g_settings->set("enable_damage", itos(menudata.enable_damage));
                                
@@ -1643,12 +1648,9 @@ int main(int argc, char *argv[])
                        }
                        
                        // Break out of menu-game loop to shut down cleanly
-                       if(device->run() == false)
+                       if(device->run() == false || kill == true)
                                break;
                        
-                       // Initialize mapnode again to enable changed graphics settings
-                       init_mapnode();
-
                        /*
                                Run game
                        */
@@ -1664,7 +1666,8 @@ int main(int argc, char *argv[])
                                address,
                                port,
                                error_message,
-                               configpath
+                               configpath,
+                               chat_backend
                        );
 
                } //try
@@ -1678,6 +1681,11 @@ int main(int argc, char *argv[])
                        errorstream<<"Socket error (port already in use?)"<<std::endl;
                        error_message = L"Socket error (port already in use?)";
                }
+               catch(ModError &e)
+               {
+                       errorstream<<e.what()<<std::endl;
+                       error_message = narrow_to_wide(e.what()) + L"\nCheck debug.txt for details.";
+               }
 #ifdef NDEBUG
                catch(std::exception &e)
                {
@@ -1697,6 +1705,8 @@ int main(int argc, char *argv[])
                In the end, delete the Irrlicht device.
        */
        device->drop();
+
+#endif // !SERVER
        
        END_DEBUG_EXCEPTION_HANDLER(errorstream)