]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/main.cpp
Tune "Connecting to server" and "Waiting content" screens
[dragonfireclient.git] / src / main.cpp
index 3bc7ca5f6a7cd126be56823582c91d17a562f75f..10e01be2ad006a6d0fd2f92263839d4adc8a91d7 100644 (file)
@@ -54,23 +54,11 @@ 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
+2983455799928051958:
+       Enormous jungle + a surface dungeon at ~(250,0,0)
 
 Old, wild and random suggestions that probably won't be done:
 -------------------------------------------------------------
@@ -328,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.
 
@@ -350,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.
@@ -359,8 +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
-
 Making it more portable:
 ------------------------
  
@@ -381,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
@@ -394,18 +373,22 @@ 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
 
+#include "main.h"
+#include "mainmenumanager.h"
 #include <iostream>
 #include <fstream>
 #include <locale.h>
-#include "main.h"
 #include "common_irrlicht.h"
 #include "debug.h"
 #include "test.h"
@@ -417,40 +400,55 @@ 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"
-
-// This makes textures
-ITextureSource *g_texturesource = NULL;
+#include "settings.h"
+#include "profiler.h"
+#include "log.h"
+#include "mods.h"
 
 /*
        Settings.
        These are loaded from the config file.
 */
-
-Settings g_settings;
-// This is located in defaultsettings.cpp
-extern void set_default_settings();
+Settings main_settings;
+Settings *g_settings = &main_settings;
 
 // Global profiler
-Profiler g_profiler;
+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
 /*
-       GUI Stuff
+       Random stuff
 */
 
+/* mainmenumanager.h */
+
 gui::IGUIEnvironment* guienv = NULL;
 gui::IGUIStaticText *guiroot = NULL;
-
 MainMenuManager g_menumgr;
 
 bool noMenuActive()
@@ -459,32 +457,22 @@ 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 = &dstream_no_stderr;
-//std::ostream *dout_con_ptr = &dstream_no_stderr;
-//std::ostream *derr_con_ptr = &dstream_no_stderr;
-//std::ostream *dout_con_ptr = &dstream;
-//std::ostream *derr_con_ptr = &dstream;
-
-// Server
-std::ostream *dout_server_ptr = &dstream;
-std::ostream *derr_server_ptr = &dstream;
+#ifdef SERVER
 
-// Client
-std::ostream *dout_client_ptr = &dstream;
-std::ostream *derr_client_ptr = &dstream;
+u32 getTimeMs()
+{
+       /* Use imprecise system calls directly (from porting.h) */
+       return porting::getTimeMs();
+}
 
-/*
-       gettime.h implementation
-*/
+#else
 
 // A small helper class
 class TimeGetter
@@ -530,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
 
@@ -554,10 +566,12 @@ class MyEventReceiver : public IEventReceiver
                // Remember whether each key is down or up
                if(event.EventType == irr::EET_KEY_INPUT_EVENT)
                {
-                       keyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
-
-                       if(event.KeyInput.PressedDown)
-                               keyWasDown[event.KeyInput.Key] = true;
+                       if(event.KeyInput.PressedDown) {
+                               keyIsDown.set(event.KeyInput);
+                               keyWasDown.set(event.KeyInput);
+                       } else {
+                               keyIsDown.unset(event.KeyInput);
+                       }
                }
 
                if(event.EventType == irr::EET_MOUSE_INPUT_EVENT)
@@ -570,7 +584,6 @@ class MyEventReceiver : public IEventReceiver
                        }
                        else
                        {
-                               //dstream<<"MyEventReceiver: mouse input"<<std::endl;
                                left_active = event.MouseInput.isLeftPressed();
                                middle_active = event.MouseInput.isMiddlePressed();
                                right_active = event.MouseInput.isRightPressed();
@@ -601,16 +614,17 @@ class MyEventReceiver : public IEventReceiver
                return false;
        }
 
-       bool IsKeyDown(EKEY_CODE keyCode) const
+       bool IsKeyDown(const KeyPress &keyCode) const
        {
                return keyIsDown[keyCode];
        }
        
        // Checks whether a key was down and resets the state
-       bool WasKeyDown(EKEY_CODE keyCode)
+       bool WasKeyDown(const KeyPress &keyCode)
        {
                bool b = keyWasDown[keyCode];
-               keyWasDown[keyCode] = false;
+               if (b)
+                       keyWasDown.unset(keyCode);
                return b;
        }
 
@@ -623,12 +637,9 @@ class MyEventReceiver : public IEventReceiver
 
        void clearInput()
        {
-               for(u32 i=0; i<KEY_KEY_CODES_COUNT; i++)
-               {
-                       keyIsDown[i] = false;
-                       keyWasDown[i] = false;
-               }
-               
+               keyIsDown.clear();
+               keyWasDown.clear();
+
                leftclicked = false;
                rightclicked = false;
                leftreleased = false;
@@ -661,9 +672,9 @@ class MyEventReceiver : public IEventReceiver
        IrrlichtDevice *m_device;
        
        // The current state of keys
-       bool keyIsDown[KEY_KEY_CODES_COUNT];
+       KeyList keyIsDown;
        // Whether a key has been pressed or not
-       bool keyWasDown[KEY_KEY_CODES_COUNT];
+       KeyList keyWasDown;
 };
 
 /*
@@ -678,11 +689,11 @@ class RealInputHandler : public InputHandler
                m_receiver(receiver)
        {
        }
-       virtual bool isKeyDown(EKEY_CODE keyCode)
+       virtual bool isKeyDown(const KeyPress &keyCode)
        {
                return m_receiver->IsKeyDown(keyCode);
        }
-       virtual bool wasKeyDown(EKEY_CODE keyCode)
+       virtual bool wasKeyDown(const KeyPress &keyCode)
        {
                return m_receiver->WasKeyDown(keyCode);
        }
@@ -763,14 +774,13 @@ class RandomInputHandler : public InputHandler
                rightclicked = false;
                leftreleased = false;
                rightreleased = false;
-               for(u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
-                       keydown[i] = false;
+               keydown.clear();
        }
-       virtual bool isKeyDown(EKEY_CODE keyCode)
+       virtual bool isKeyDown(const KeyPress &keyCode)
        {
                return keydown[keyCode];
        }
-       virtual bool wasKeyDown(EKEY_CODE keyCode)
+       virtual bool wasKeyDown(const KeyPress &keyCode)
        {
                return false;
        }
@@ -839,8 +849,7 @@ class RandomInputHandler : public InputHandler
                        if(counter1 < 0.0)
                        {
                                counter1 = 0.1*Rand(1, 40);
-                               keydown[getKeySetting("keymap_jump")] =
-                                               !keydown[getKeySetting("keymap_jump")];
+                               keydown.toggle(getKeySetting("keymap_jump"));
                        }
                }
                {
@@ -849,8 +858,7 @@ class RandomInputHandler : public InputHandler
                        if(counter1 < 0.0)
                        {
                                counter1 = 0.1*Rand(1, 40);
-                               keydown[getKeySetting("keymap_special1")] =
-                                               !keydown[getKeySetting("keymap_special1")];
+                               keydown.toggle(getKeySetting("keymap_special1"));
                        }
                }
                {
@@ -859,8 +867,7 @@ class RandomInputHandler : public InputHandler
                        if(counter1 < 0.0)
                        {
                                counter1 = 0.1*Rand(1, 40);
-                               keydown[getKeySetting("keymap_forward")] =
-                                               !keydown[getKeySetting("keymap_forward")];
+                               keydown.toggle(getKeySetting("keymap_forward"));
                        }
                }
                {
@@ -869,8 +876,7 @@ class RandomInputHandler : public InputHandler
                        if(counter1 < 0.0)
                        {
                                counter1 = 0.1*Rand(1, 40);
-                               keydown[getKeySetting("keymap_left")] =
-                                               !keydown[getKeySetting("keymap_left")];
+                               keydown.toggle(getKeySetting("keymap_left"));
                        }
                }
                {
@@ -916,7 +922,7 @@ class RandomInputHandler : public InputHandler
                return (myrand()%(max-min+1))+min;
        }
 private:
-       bool keydown[KEY_KEY_CODES_COUNT];
+       KeyList keydown;
        v2s32 mousepos;
        v2s32 mousespeed;
        bool leftdown;
@@ -927,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;
@@ -939,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++)
@@ -958,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;
 
        {
@@ -1001,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;
@@ -1020,64 +1075,22 @@ void SpeedTests()
 
                u32 dtime = timer.stop();
                u32 per_ms = n / dtime;
-               std::cout<<"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);
-       }
-}
-
 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
@@ -1089,21 +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));
 
        Settings cmd_args;
        
@@ -1140,31 +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") || 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);
 
-       setlocale(LC_MESSAGES, "");
-       bindtextdomain("minetest", (porting::path_userdata+"/locale").c_str());
-       textdomain("minetest");
+       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+"/"+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();
@@ -1178,7 +1195,7 @@ int main(int argc, char *argv[])
        BEGIN_DEBUG_EXCEPTION_HANDLER
 
        // Print startup message
-       dstream<<DTIME<<"minetest-c55"
+       actionstream<<PROJECT_NAME<<
                        " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST
                        <<", "<<BUILD_INFO
                        <<std::endl;
@@ -1188,7 +1205,7 @@ int main(int argc, char *argv[])
        */
 
        // Initialize default settings
-       set_default_settings();
+       set_default_settings(g_settings);
        
        // Initialize sockets
        sockets_init();
@@ -1203,10 +1220,10 @@ int main(int argc, char *argv[])
        
        if(cmd_args.exists("config"))
        {
-               bool r = g_settings.readConfigFile(cmd_args.get("config").c_str());
+               bool r = g_settings->readConfigFile(cmd_args.get("config").c_str());
                if(r == false)
                {
-                       dstream<<"Could not read configuration from \""
+                       errorstream<<"Could not read configuration from \""
                                        <<cmd_args.get("config")<<"\""<<std::endl;
                        return 1;
                }
@@ -1215,14 +1232,21 @@ int main(int argc, char *argv[])
        else
        {
                core::array<std::string> filenames;
-               filenames.push_back(porting::path_userdata + "/minetest.conf");
+               filenames.push_back(porting::path_user +
+                               DIR_DELIM + "minetest.conf");
+               // Legacy configuration file location
+               filenames.push_back(porting::path_user +
+                               DIR_DELIM + ".." + DIR_DELIM + "minetest.conf");
 #ifdef RUN_IN_PLACE
-               filenames.push_back(porting::path_userdata + "/../minetest.conf");
+               // 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++)
                {
-                       bool r = g_settings.readConfigFile(filenames[i].c_str());
+                       bool r = g_settings->readConfigFile(filenames[i].c_str());
                        if(r)
                        {
                                configpath = filenames[i];
@@ -1239,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
        */
@@ -1258,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
        */
@@ -1273,36 +1281,65 @@ int main(int argc, char *argv[])
        u16 port = 30000;
        if(cmd_args.exists("port"))
                port = cmd_args.getU16("port");
-       else if(g_settings.exists("port"))
-               port = g_settings.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";
+       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 if(g_settings->exists("map-dir"))
+               map_dir = g_settings->get("map-dir");
+       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());
+               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
@@ -1317,10 +1354,10 @@ int main(int argc, char *argv[])
        }
        else
        {
-               address = g_settings.get("address");
+               address = g_settings->get("address");
        }
        
-       std::string playername = g_settings.get("name");
+       std::string playername = g_settings->get("name");
 
        /*
                Device initialization
@@ -1329,14 +1366,14 @@ int main(int argc, char *argv[])
        // Resolution selection
        
        bool fullscreen = false;
-       u16 screenW = g_settings.getU16("screenW");
-       u16 screenH = g_settings.getU16("screenH");
+       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");
+       std::string driverstring = g_settings->get("video_driver");
 
        if(driverstring == "null")
                driverType = video::EDT_NULL;
@@ -1352,7 +1389,7 @@ int main(int argc, char *argv[])
                driverType = video::EDT_OPENGL;
        else
        {
-               dstream<<"WARNING: Invalid video_driver specified; defaulting "
+               errorstream<<"WARNING: Invalid video_driver specified; defaulting "
                                "to opengl"<<std::endl;
                driverType = video::EDT_OPENGL;
        }
@@ -1371,8 +1408,20 @@ int main(int argc, char *argv[])
        if (device == 0)
                return 1; // could not create selected driver.
        
-       // Set device in game parameters
-       device = device;
+       /*
+               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]");
@@ -1383,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)
        */
@@ -1398,7 +1444,7 @@ int main(int argc, char *argv[])
        
        device->setResizable(true);
 
-       bool random_input = g_settings.getBool("random_input")
+       bool random_input = g_settings->getBool("random_input")
                        || cmd_args.getFlag("random-input");
        InputHandler *input = NULL;
        if(random_input)
@@ -1406,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();
@@ -1426,14 +1460,14 @@ int main(int argc, char *argv[])
        if(font)
                skin->setFont(font);
        else
-               dstream<<"WARNING: Font file was not found."
+               errorstream<<"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;
+       infostream<<"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));
@@ -1442,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
@@ -1509,10 +1538,12 @@ int main(int argc, char *argv[])
                                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");
+                               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");
 
                                GUIMainMenu *menu =
                                                new GUIMainMenu(guienv, guiroot, -1, 
@@ -1521,7 +1552,7 @@ int main(int argc, char *argv[])
 
                                if(error_message != L"")
                                {
-                                       dstream<<"WARNING: error_message = "
+                                       errorstream<<"error_message = "
                                                        <<wide_to_narrow(error_message)<<std::endl;
 
                                        GUIMessageMenu *menu2 =
@@ -1533,7 +1564,7 @@ int main(int argc, char *argv[])
 
                                video::IVideoDriver* driver = device->getVideoDriver();
                                
-                               dstream<<"Created main menu"<<std::endl;
+                               infostream<<"Created main menu"<<std::endl;
 
                                while(device->run() && kill == false)
                                {
@@ -1558,7 +1589,7 @@ int main(int argc, char *argv[])
                                if(device->run() == false || kill == true)
                                        break;
                                
-                               dstream<<"Dropping main menu"<<std::endl;
+                               infostream<<"Dropping main menu"<<std::endl;
 
                                menu->drop();
                                
@@ -1575,14 +1606,18 @@ int main(int argc, char *argv[])
 
                                password = translatePassword(playername, menudata.password);
 
+                               //infostream<<"Main: password hash: '"<<password<<"'"<<std::endl;
+
                                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));
+                               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));
                                
                                // NOTE: These are now checked server side; no need to do it
                                //       here, so let's not do it here.
@@ -1601,24 +1636,21 @@ int main(int argc, char *argv[])
                                }*/
 
                                // Save settings
-                               g_settings.set("name", playername);
-                               g_settings.set("address", address);
-                               g_settings.set("port", itos(port));
+                               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());
+                                       g_settings->updateConfigFile(configpath.c_str());
                        
                                // Continue to game
                                break;
                        }
                        
                        // 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
                        */
@@ -1633,27 +1665,34 @@ int main(int argc, char *argv[])
                                password,
                                address,
                                port,
-                               error_message
+                               error_message,
+                               configpath,
+                               chat_backend
                        );
 
                } //try
                catch(con::PeerNotFoundException &e)
                {
-                       dstream<<DTIME<<"Connection error (timed out?)"<<std::endl;
+                       errorstream<<"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;
+                       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)
                {
                        std::string narrow_message = "Some exception, what()=\"";
                        narrow_message += e.what();
                        narrow_message += "\"";
-                       dstream<<DTIME<<narrow_message<<std::endl;
+                       errorstream<<narrow_message<<std::endl;
                        error_message = narrow_to_wide(narrow_message);
                }
 #endif
@@ -1666,8 +1705,10 @@ int main(int argc, char *argv[])
                In the end, delete the Irrlicht device.
        */
        device->drop();
+
+#endif // !SERVER
        
-       END_DEBUG_EXCEPTION_HANDLER
+       END_DEBUG_EXCEPTION_HANDLER(errorstream)
        
        debugstreams_deinit();