sitä sun tätä tekeillä, toimii kivasti
authorPerttu Ahola <celeron55@gmail.com>
Mon, 29 Nov 2010 08:52:07 +0000 (10:52 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Mon, 29 Nov 2010 08:52:07 +0000 (10:52 +0200)
19 files changed:
Makefile
data/mud.png [new file with mode: 0644]
makepackage_binary.sh
minetest.conf.example
src/client.cpp
src/constants.h
src/exceptions.h
src/main.cpp
src/main.h
src/map.cpp
src/map.h
src/mapblock.h
src/mapnode.h
src/mapsector.h
src/server.cpp
src/server.h
src/socket.cpp
src/test.cpp
src/utility.h

index c8912d1ff6905b7c2a76b8fad7f0e9376aa2112c..979631fc0f79b1405a86bbf54958e92eda8b5652 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 # It's usually sufficient to change just the target name and source file list\r
 # and be sure that CXX is set to a valid compiler\r
 TARGET = test\r
-SOURCE_FILES = mapblockobject.cpp inventory.cpp debug.cpp serialization.cpp light.cpp filesys.cpp connection.cpp environment.cpp client.cpp server.cpp socket.cpp mapblock.cpp mapsector.cpp heightmap.cpp map.cpp player.cpp utility.cpp main.cpp test.cpp\r
+SOURCE_FILES = voxel.cpp mapblockobject.cpp inventory.cpp debug.cpp serialization.cpp light.cpp filesys.cpp connection.cpp environment.cpp client.cpp server.cpp socket.cpp mapblock.cpp mapsector.cpp heightmap.cpp map.cpp player.cpp utility.cpp main.cpp test.cpp\r
 SOURCES = $(addprefix src/, $(SOURCE_FILES))\r
 OBJECTS = $(SOURCES:.cpp=.o)\r
 FASTTARGET = fasttest\r
@@ -13,7 +13,7 @@ JTHREADPATH = ../jthread/jthread-1.2.1
 CPPFLAGS = -I$(IRRLICHTPATH)/include -I/usr/X11R6/include -I$(JTHREADPATH)/src\r
 \r
 #CXXFLAGS = -O2 -ffast-math -Wall -fomit-frame-pointer -pipe\r
-CXXFLAGS = -O2 -ffast-math -Wall -g\r
+CXXFLAGS = -O2 -ffast-math -Wall -g -pipe\r
 #CXXFLAGS = -O1 -ffast-math -Wall -g\r
 #CXXFLAGS = -Wall -g -O0\r
 \r
@@ -21,8 +21,8 @@ CXXFLAGS = -O2 -ffast-math -Wall -g
 #CXXFLAGS = -O3 -ffast-math -Wall -g\r
 #CXXFLAGS = -O2 -ffast-math -Wall -g\r
 \r
-#FASTCXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=pentium3\r
-FASTCXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=i686\r
+#FASTCXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=i686\r
+FASTCXXFLAGS = -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops -mtune=i686 -fwhole-program\r
 \r
 #Default target\r
 \r
@@ -53,7 +53,9 @@ all_linux all_win32: $(DESTPATH)
 fast_linux: $(FASTDESTPATH)\r
 \r
 $(FASTDESTPATH): $(SOURCES)\r
-       $(CXX) -o $(FASTDESTPATH) $(SOURCES) $(CPPFLAGS) $(FASTCXXFLAGS) $(LDFLAGS) -DUNITTEST_DISABLE\r
+       @#$(CXX) -o $(FASTDESTPATH) $(SOURCES) $(CPPFLAGS) $(FASTCXXFLAGS) $(LDFLAGS) -DUNITTEST_DISABLE\r
+       @# Errno doesn't work ("error: ‘__errno_location’ was not declared in this scope")\r
+       cat $(SOURCES) | $(CXX) -o $(FASTDESTPATH) -x c++ - -Isrc/ $(CPPFLAGS) $(FASTCXXFLAGS) $(LDFLAGS) -DUNITTEST_DISABLE -DDISABLE_ERRNO\r
 \r
 $(DESTPATH): $(OBJECTS)\r
        $(CXX) -o $@ $(OBJECTS) $(LDFLAGS)\r
diff --git a/data/mud.png b/data/mud.png
new file mode 100644 (file)
index 0000000..0c6925d
Binary files /dev/null and b/data/mud.png differ
index c11c45b183a3fc261651a028a7d9de57d1e86f40..38a3012949b6ec21891a841b5ed75ee166badfd0 100755 (executable)
@@ -32,6 +32,7 @@ cp -r data/light.png $PACKAGEPATH/data/
 cp -r data/sign.png $PACKAGEPATH/data/
 cp -r data/sign_back.png $PACKAGEPATH/data/
 cp -r data/rat.png $PACKAGEPATH/data/
+cp -r data/mud.png $PACKAGEPATH/data/
 
 cp -r doc/README.txt $PACKAGEPATH/doc/README.txt
 
index 172032f400e6dea8bef0c5d43231986f180b51f0..6aa16917ef284211ed2604ca5111a5b4f45dc29a 100644 (file)
@@ -44,4 +44,8 @@ creative_mode = false
 # Player and object positions are sent at intervals specified by this
 objectdata_inverval = 0.2
 
+active_object_range = 2
+
+max_simultaneous_block_sends_per_client = 2
+max_simultaneous_block_sends_server_total = 4
 
index a4f0ffb07f9a838ff30f2edcad9bde6bf038fea0..cf9feed7d470ed09cc4413e0092469d2481a86a9 100644 (file)
@@ -31,7 +31,7 @@ void * ClientUpdateThread::Thread()
                        bool was = m_client->AsyncProcessData();
 
                        if(was == false)
-                               sleep_ms(50);
+                               sleep_ms(10);
                }
 #if CATCH_UNHANDLED_EXCEPTIONS
        }
@@ -159,13 +159,17 @@ void Client::step(float dtime)
        {
                /*
                        Delete unused sectors
+
+                       NOTE: This jams the game for a while because deleting sectors
+                             clear caches
                */
                
                static float counter = -0.001;
                counter -= dtime;
                if(counter <= 0.0)
                {
-                       counter = 10.0;
+                       // 3 minute interval
+                       counter = 180.0;
 
                        JMutexAutoLock lock(m_env_mutex);
 
@@ -381,6 +385,8 @@ float Client::asyncStep()
        /*float dtime;
        {
                JMutexAutoLock lock1(m_step_dtime_mutex);
+               if(m_step_dtime < 0.001)
+                       return 0.0;
                dtime = m_step_dtime;
                m_step_dtime = 0.0;
        }
@@ -1207,14 +1213,26 @@ bool Client::AsyncProcessPacket(LazyMeshUpdater &mesh_updater)
 
 bool Client::AsyncProcessData()
 {
-       LazyMeshUpdater mesh_updater(&m_env);
        for(;;)
        {
+               // We want to update the meshes as soon as a single packet has
+               // been processed
+               LazyMeshUpdater mesh_updater(&m_env);
                bool r = AsyncProcessPacket(mesh_updater);
                if(r == false)
                        break;
        }
        return false;
+
+       /*
+       LazyMeshUpdater mesh_updater(&m_env);
+       for(;;)
+       {
+               bool r = AsyncProcessPacket(mesh_updater);
+               if(r == false)
+                       break;
+       }
+       return false;*/
 }
 
 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
index f7ff0aef1488857547b8ee7d5d951c3cf2f69e98..8cc4ee473aa6338d94648dd67ea80edfea85369e 100644 (file)
 // The absolute working limit is (2^15 - viewing_range).
 #define MAP_GENERATION_LIMIT (31000)
 
-#define MAX_SIMULTANEOUS_BLOCK_SENDS 2
+//#define MAX_SIMULTANEOUS_BLOCK_SENDS 2
 
 #define FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING 2.0
-#define LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS 1
+//#define LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS 1
+#define LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS 0
 
-#define MAX_SIMULTANEOUS_BLOCK_SENDS_SERVER_TOTAL 4
+// Override for the previous one when distance is low
+#define BLOCK_SEND_DISABLE_LIMITS_MAX_D 1
 
-// Viewing range stuff
+//#define MAX_SIMULTANEOUS_BLOCK_SENDS_SERVER_TOTAL 4
 
-#define FPS_DEFAULT_WANTED 30
-#define FPS_DEFAULT_MAX 60
+// Viewing range stuff
 
-#define HEIGHTMAP_RANGE_NODES 300
+//#define HEIGHTMAP_RANGE_NODES 300
 
 //#define FREETIME_RATIO 0.2
 #define FREETIME_RATIO 0.15
@@ -56,7 +57,7 @@
 //#define ACTIVE_OBJECT_D_BLOCKS 2
 
 // Wether to catch all std::exceptions
-#define CATCH_UNJANDLED_EXCEPTIONS 1
+#define CATCH_UNHANDLED_EXCEPTIONS 0
 
 /*
        Collecting active blocks is stopped after object data
index cbe13f1f359eab34a71411bc0ee5488f01224488..3e939a08616c75bc6fae507fcba94c8a7af1c155 100644 (file)
@@ -81,6 +81,22 @@ public:
        {}
 };
 
+class SettingNotFoundException : public BaseException
+{
+public:
+       SettingNotFoundException(const char *s):
+               BaseException(s)
+       {}
+};
+
+class InvalidFilenameException : public BaseException
+{
+public:
+       InvalidFilenameException(const char *s):
+               BaseException(s)
+       {}
+};
+
 /*
        Some "old-style" interrupts:
 */
index 258119c4a233d5963b3a08f2d087502350e4e93f..991185ca6b89fe2bf1e5f5bd4a99c40ac3f32766 100644 (file)
@@ -21,11 +21,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 =============================== NOTES ==============================\r
 \r
 NOTE: VBO cannot be turned on for fast-changing stuff because there\r
-      is an apparanet memory leak in irrlicht when using it\r
+      is an apparanet memory leak in irrlicht when using it (not sure)\r
+\r
+NOTE: iostream.imbue(std::locale("C")) is very slow\r
+NOTE: Global locale is now set at initialization\r
 \r
 SUGGESTION: add a second lighting value to the MS nibble of param of\r
        air to tell how bright the air node is when there is no sunlight.\r
        When day changes to night, these two values can be interpolated.\r
+\r
 TODO: Fix address to be ipv6 compatible\r
 \r
 TODO: ESC Pause mode in which the cursor is not kept at the center of window.\r
@@ -93,9 +97,7 @@ TODO: Expose Connection's seqnums and ACKs to server and client.
          - This also enables server to check if client has received the\r
            most recent block sent, for example.\r
 \r
-SUGG: Add a time value to the param of footstepped grass and check it\r
-      against a global timer when a block is accessed, to make old\r
-         steps fade away.\r
+TODO: Add a sane bandwidth throttling system to Connection\r
 \r
 FIXME: There still are *some* tiny glitches in lighting as seen from\r
        the client side. The server calculates them right but sometimes\r
@@ -105,8 +107,9 @@ FIXME: There still are *some* tiny glitches in lighting as seen from
           the sender sends the block as it was before emerging?\r
 TODO: How about adding a "revision" field to MapBlocks?\r
 \r
-TODO: More fine-grained control of client's dumping of blocks from\r
+SUGG: More fine-grained control of client's dumping of blocks from\r
       memory\r
+         - ...What does this mean in the first place?\r
 \r
 TODO: Somehow prioritize the sending of blocks and combine the block\r
       send queue lengths\r
@@ -130,9 +133,6 @@ SUGG: Make client send GOTBLOCKS before updating meshes
 \r
 TODO: Server to load starting inventory from disk\r
 \r
-NOTE: iostream.imbue(std::locale("C")) is very slow\r
-NOTE: Global locale is now set at initialization\r
-\r
 TODO: PLayers to only be hidden when the client quits.\r
 TODO: - Players to be saved on disk, with inventory\r
 TODO: Players to be saved as text in map/players/<name>\r
@@ -158,12 +158,18 @@ Block object server side:
       - A "near blocks" buffer, in which some nearby blocks are stored.\r
          - For all blocks in the buffer, objects are stepped(). This\r
            means they are active.\r
-      - TODO All blocks going in and out of the buffer are recorded.\r
-           - TODO For outgoing blocks, a timestamp is written.\r
-           - TODO For incoming blocks, the time difference is calculated and\r
+         - TODO: A global active buffer is needed for the server\r
+      - TODO: All blocks going in and out of the buffer are recorded.\r
+           - TODO: For outgoing blocks, a timestamp is written.\r
+           - TODO: For incoming blocks, the time difference is calculated and\r
              objects are stepped according to it.\r
 TODO: A timestamp to blocks\r
 \r
+SUGG: Add a time value to the param of footstepped grass and check it\r
+      against a global timer when a block is accessed, to make old\r
+         steps fade away.\r
+\r
+\r
 TODO: Add config parameters for server's sending and generating distance\r
 \r
 TODO: Copy the text of the last picked sign to inventory in creative\r
@@ -185,12 +191,16 @@ SUGG: Split MapBlockObject serialization to to-client and to-disk
       - This will allow saving ages of rats on disk but not sending\r
            them to clients\r
 \r
-TODO: Fix the long-lived Server Block Emerge Jam bug\r
-      - Is it related to the client deleting blocks?\r
+TODO: Get rid of GotSplitPacketException\r
+\r
+Before release:\r
+\r
+TODO: Check what goes wrong with caching map to disk (Kray)\r
 \r
 Doing now:\r
 ======================================================================\r
 \r
+TODO: Implement lighting using VoxelManipulator\r
 \r
 ======================================================================\r
 \r
@@ -202,7 +212,7 @@ Doing now:
        the starting place to a static direction.\r
 \r
        This allows one to move around with the player and see what\r
-       is actually drawn behind solid things etc.\r
+       is actually drawn behind solid things and behind the player.\r
 */\r
 #define FIELD_OF_VIEW_TEST 0\r
 \r
@@ -265,7 +275,8 @@ const char *g_material_filenames[MATERIALS_COUNT] =
        "../data/tree.png",\r
        "../data/leaves.png",\r
        "../data/grass_footsteps.png",\r
-       "../data/mese.png"\r
+       "../data/mese.png",\r
+       "../data/mud.png"\r
 };\r
 \r
 video::SMaterial g_materials[MATERIALS_COUNT];\r
@@ -296,28 +307,39 @@ bool g_viewing_range_all = false;
        These are loaded from the config file.\r
 */\r
 \r
-std::string g_dedicated_server;\r
-\r
-// Client stuff\r
-float g_wanted_fps = FPS_DEFAULT_WANTED;\r
-float g_fps_max = FPS_DEFAULT_MAX;\r
-s16 g_viewing_range_nodes_max = 300;\r
-s16 g_viewing_range_nodes_min = 20;\r
-std::string g_screenW;\r
-std::string g_screenH;\r
-std::string g_host_game;\r
-std::string g_port;\r
-std::string g_address;\r
-std::string g_name;\r
-bool g_random_input = false;\r
-float g_client_delete_unused_sectors_timeout = 1200;\r
-\r
-// Server stuff\r
-bool g_creative_mode = false;\r
-HMParams g_hm_params;\r
-MapParams g_map_params;\r
-float g_objectdata_interval = 0.2;\r
-u16 g_active_object_range = 2;\r
+Settings g_settings;\r
+\r
+// Sets default settings\r
+void set_default_settings()\r
+{\r
+       g_settings.set("dedicated_server", "");\r
+\r
+       // Client stuff\r
+       g_settings.set("wanted_fps", "30");\r
+       g_settings.set("fps_max", "60");\r
+       g_settings.set("viewing_range_nodes_max", "300");\r
+       g_settings.set("viewing_range_nodes_min", "20");\r
+       g_settings.set("screenW", "");\r
+       g_settings.set("screenH", "");\r
+       g_settings.set("host_game", "");\r
+       g_settings.set("port", "");\r
+       g_settings.set("address", "");\r
+       g_settings.set("name", "");\r
+       g_settings.set("random_input", "false");\r
+       g_settings.set("client_delete_unused_sectors_timeout", "1200");\r
+\r
+       // Server stuff\r
+       g_settings.set("creative_mode", "false");\r
+       g_settings.set("heightmap_blocksize", "128");\r
+       g_settings.set("height_randmax", "constant 70.0");\r
+       g_settings.set("height_randfactor", "constant 0.6");\r
+       g_settings.set("height_base", "linear 0 35 0");\r
+       g_settings.set("plants_amount", "1.0");\r
+       g_settings.set("objectdata_interval", "0.2");\r
+       g_settings.set("active_object_range", "2");\r
+       g_settings.set("max_simultaneous_block_sends_per_client", "2");\r
+       g_settings.set("max_simultaneous_block_sends_server_total", "4");\r
+}\r
 \r
 /*\r
        Random stuff\r
@@ -354,144 +376,6 @@ std::ostream *derr_server_ptr = &dstream;
 std::ostream *dout_client_ptr = &dstream;\r
 std::ostream *derr_client_ptr = &dstream;\r
 \r
-/*\r
-       Config stuff\r
-*/\r
-\r
-// Returns false on EOF\r
-bool parseConfigObject(std::istream &is)\r
-{\r
-       // float g_wanted_fps\r
-       // s16 g_viewing_range_nodes_max\r
-\r
-       if(is.eof())\r
-               return false;\r
-       \r
-       std::string line;\r
-       std::getline(is, line);\r
-       //dstream<<"got line: \""<<line<<"\""<<std::endl;\r
-\r
-       std::string trimmedline = trim(line);\r
-       \r
-       // Ignore comments\r
-       if(trimmedline[0] == '#')\r
-               return true;\r
-\r
-       //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;\r
-\r
-       Strfnd sf(trim(line));\r
-\r
-       std::string name = sf.next("=");\r
-       name = trim(name);\r
-\r
-       if(name == "")\r
-               return true;\r
-       \r
-       std::string value = sf.next("\n");\r
-       value = trim(value);\r
-\r
-       dstream<<"Config name=\""<<name<<"\" value=\""\r
-                       <<value<<"\""<<std::endl;\r
-       \r
-       if(name == "dedicated_server")\r
-               g_dedicated_server = value;\r
-       \r
-       // Client stuff\r
-       else if(name == "wanted_fps")\r
-       {\r
-               g_wanted_fps = atof(value.c_str());\r
-       }\r
-       else if(name == "fps_max")\r
-       {\r
-               g_fps_max = atof(value.c_str());\r
-       }\r
-       else if(name == "viewing_range_nodes_max")\r
-       {\r
-               g_viewing_range_nodes_max = stoi(value, 0, 32767);\r
-       }\r
-       else if(name == "viewing_range_nodes_min")\r
-       {\r
-               g_viewing_range_nodes_min = stoi(value, 0, 32767);\r
-       }\r
-       else if(name=="screenW")\r
-               g_screenW = value;\r
-       else if(name=="screenH")\r
-               g_screenH = value;\r
-       else if(name == "host_game")\r
-               g_host_game = value;\r
-       else if(name == "port")\r
-               g_port = value;\r
-       else if(name == "address")\r
-               g_address = value;\r
-       else if(name == "name")\r
-               g_name = value;\r
-       else if(name == "random_input")\r
-               g_random_input = is_yes(value);\r
-       else if(name == "client_delete_unused_sectors_timeout")\r
-       {\r
-               std::istringstream vis(value);\r
-               //vis.imbue(std::locale("C"));\r
-               vis>>g_client_delete_unused_sectors_timeout;\r
-       }\r
-       \r
-       // Server stuff\r
-       else if(name == "creative_mode")\r
-               g_creative_mode = is_yes(value);\r
-       else if(name == "mapgen_heightmap_blocksize")\r
-       {\r
-               s32 d = atoi(value.c_str());\r
-               if(d > 0 && (d & (d-1)) == 0)\r
-                       g_hm_params.heightmap_blocksize = d;\r
-               else\r
-                       dstream<<"Invalid value in config file: \""\r
-                                       <<line<<"\""<<std::endl;\r
-       }\r
-       else if(name == "mapgen_height_randmax")\r
-               g_hm_params.height_randmax = value;\r
-       else if(name == "mapgen_height_randfactor")\r
-               g_hm_params.height_randfactor = value;\r
-       else if(name == "mapgen_height_base")\r
-               g_hm_params.height_base = value;\r
-       else if(name == "mapgen_plants_amount")\r
-       {\r
-               std::istringstream vis(value);\r
-               vis>>g_map_params.plants_amount;\r
-       }\r
-       else if(name == "objectdata_inverval")\r
-       {\r
-               std::istringstream vis(value);\r
-               vis>>g_objectdata_interval;\r
-       }\r
-       else if(name == "active_object_range")\r
-               g_active_object_range = stoi(value, 0, 65535);\r
-       \r
-       else\r
-       {\r
-               dstream<<"Unknown option in config file: \""\r
-                               <<line<<"\""<<std::endl;\r
-       }\r
-\r
-       return true;\r
-}\r
-\r
-// Returns true on success\r
-bool readConfigFile(const char *filename)\r
-{\r
-       std::ifstream is(filename);\r
-       if(is.good() == false)\r
-       {\r
-               dstream<<DTIME<<"Error opening configuration file: "\r
-                               <<filename<<std::endl;\r
-               return false;\r
-       }\r
-\r
-       dstream<<DTIME<<"Parsing configuration file: "\r
-                       <<filename<<std::endl;\r
-                       \r
-       while(parseConfigObject(is));\r
-       \r
-       return true;\r
-}\r
 \r
 /*\r
        Timestamp stuff\r
@@ -875,9 +759,11 @@ void updateViewingRange(f32 frametime, Client *client)
        // Range_all messes up frametime_avg\r
        if(g_viewing_range_all == true)\r
                return;\r
+\r
+       float wanted_fps = g_settings.getFloat("wanted_fps");\r
        \r
        // Initialize to the target value\r
-       static float frametime_avg = 1.0/g_wanted_fps;\r
+       static float frametime_avg = 1.0/wanted_fps;\r
        frametime_avg = frametime_avg * 0.9 + frametime * 0.1;\r
 \r
        static f32 counter = 0;\r
@@ -892,7 +778,7 @@ void updateViewingRange(f32 frametime, Client *client)
        //float freetime_ratio = 0.4;\r
        float freetime_ratio = FREETIME_RATIO;\r
 \r
-       float frametime_wanted = (1.0/(g_wanted_fps/(1.0-freetime_ratio)));\r
+       float frametime_wanted = (1.0/(wanted_fps/(1.0-freetime_ratio)));\r
 \r
        float fraction = sqrt(frametime_avg / frametime_wanted);\r
 \r
@@ -925,11 +811,14 @@ void updateViewingRange(f32 frametime, Client *client)
 \r
        JMutexAutoLock lock(g_range_mutex);\r
        \r
+       s16 viewing_range_nodes_min = g_settings.getS16("viewing_range_nodes_min");\r
+       s16 viewing_range_nodes_max = g_settings.getS16("viewing_range_nodes_max");\r
+\r
        s16 n = (float)g_viewing_range_nodes / fraction;\r
-       if(n < g_viewing_range_nodes_min)\r
-               n = g_viewing_range_nodes_min;\r
-       if(n > g_viewing_range_nodes_max)\r
-               n = g_viewing_range_nodes_max;\r
+       if(n < viewing_range_nodes_min)\r
+               n = viewing_range_nodes_min;\r
+       if(n > viewing_range_nodes_max)\r
+               n = viewing_range_nodes_max;\r
 \r
        bool can_change = true;\r
 \r
@@ -1050,10 +939,11 @@ int main(int argc, char *argv[])
        disable_stderr = true;\r
 #endif\r
 \r
+       // Initialize debug streams\r
        debugstreams_init(disable_stderr, DEBUGFILE);\r
+       // Initialize debug stacks\r
        debug_stacks_init();\r
 \r
-\r
        DSTACK(__FUNCTION_NAME);\r
 \r
        try\r
@@ -1063,6 +953,10 @@ int main(int argc, char *argv[])
                Basic initialization\r
        */\r
 \r
+       // Initialize default settings\r
+       set_default_settings();\r
+       \r
+       // Print startup message\r
        dstream<<DTIME<<"minetest-c55"\r
                        " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST\r
                        <<", ENABLE_TESTS="<<ENABLE_TESTS\r
@@ -1096,7 +990,7 @@ int main(int argc, char *argv[])
        \r
        if(argc >= 2)\r
        {\r
-               readConfigFile(argv[1]);\r
+               g_settings.readConfigFile(argv[1]);\r
        }\r
        else\r
        {\r
@@ -1108,7 +1002,7 @@ int main(int argc, char *argv[])
 \r
                for(u32 i=0; i<2; i++)\r
                {\r
-                       bool r = readConfigFile(filenames[i]);\r
+                       bool r = g_settings.readConfigFile(filenames[i]);\r
                        if(r)\r
                                break;\r
                }\r
@@ -1120,6 +1014,17 @@ int main(int argc, char *argv[])
        g_range_mutex.Init();\r
        assert(g_range_mutex.IsInitialized());\r
 \r
+       // Read map parameters from settings\r
+\r
+       HMParams hm_params;\r
+       hm_params.blocksize = g_settings.getU16("heightmap_blocksize");\r
+       hm_params.randmax = g_settings.get("height_randmax");\r
+       hm_params.randfactor = g_settings.get("height_randfactor");\r
+       hm_params.base = g_settings.get("height_base");\r
+\r
+       MapParams map_params;\r
+       map_params.plants_amount = g_settings.getFloat("plants_amount");\r
+\r
        /*\r
                Ask some stuff\r
        */\r
@@ -1127,40 +1032,13 @@ int main(int argc, char *argv[])
        std::cout<<std::endl<<std::endl;\r
        char templine[100];\r
        \r
-       std::cout<<"Dedicated server? [y = yes]: ";\r
-       if(g_dedicated_server != "")\r
-       {\r
-               std::cout<<g_dedicated_server<<std::endl;\r
-               snprintf(templine, 100, "%s", g_dedicated_server.c_str());\r
-       }\r
-       else\r
-       {\r
-               std::cin.getline(templine, 100);\r
-       }\r
-\r
-       bool dedicated = false;\r
-       if(templine[0] == 'y')\r
-               dedicated = true;\r
-       if(dedicated)\r
-               std::cout<<"-> yes"<<std::endl;\r
-       else\r
-               std::cout<<"-> no"<<std::endl;\r
+       // Dedicated?\r
+       bool dedicated = g_settings.getBoolAsk\r
+                       ("dedicated_server", "Dedicated server?", false);\r
+       std::cout<<"dedicated = "<<dedicated<<std::endl;\r
        \r
-       std::cout<<"Port [empty=30000]: ";\r
-       if(g_port != "")\r
-       {\r
-               std::cout<<g_port<<std::endl;\r
-               snprintf(templine, 100, "%s", g_port.c_str());\r
-       }\r
-       else\r
-       {\r
-               std::cin.getline(templine, 100);\r
-       }\r
-       unsigned short port;\r
-       if(templine[0] == 0)\r
-               port = 30000;\r
-       else\r
-               port = atoi(templine);\r
+       // Port?\r
+       u16 port = g_settings.getU16Ask("port", "Port", 30000);\r
        std::cout<<"-> "<<port<<std::endl;\r
        \r
        if(dedicated)\r
@@ -1173,17 +1051,15 @@ int main(int argc, char *argv[])
                std::cout<<"========================"<<std::endl;\r
                std::cout<<std::endl;\r
 \r
-               Server server("../map", g_creative_mode, g_hm_params,\r
-                               g_map_params, g_objectdata_interval,\r
-                               g_active_object_range);\r
+               Server server("../map", hm_params, map_params);\r
                server.start(port);\r
        \r
                for(;;)\r
                {\r
                        // This is kind of a hack but can be done like this\r
                        // because server.step() is very light\r
-                       sleep_ms(100);\r
-                       server.step(0.1);\r
+                       sleep_ms(30);\r
+                       server.step(0.030);\r
 \r
                        static int counter = 0;\r
                        counter--;\r
@@ -1214,10 +1090,10 @@ int main(int argc, char *argv[])
        char connect_name[100] = "";\r
 \r
        std::cout<<"Address to connect to [empty = host a game]: ";\r
-       if(g_address != "" && is_yes(g_host_game) == false)\r
+       if(g_settings.get("address") != "" && is_yes(g_settings.get("host_game")) == false)\r
        {\r
-               std::cout<<g_address<<std::endl;\r
-               snprintf(connect_name, 100, "%s", g_address.c_str());\r
+               std::cout<<g_settings.get("address")<<std::endl;\r
+               snprintf(connect_name, 100, "%s", g_settings.get("address").c_str());\r
        }\r
        else\r
        {\r
@@ -1235,9 +1111,9 @@ int main(int argc, char *argv[])
                std::cout<<"-> "<<connect_name<<std::endl;\r
        \r
        char playername[PLAYERNAME_SIZE] = "";\r
-       if(g_name != "")\r
+       if(g_settings.get("name") != "")\r
        {\r
-               snprintf(playername, PLAYERNAME_SIZE, "%s", g_name.c_str());\r
+               snprintf(playername, PLAYERNAME_SIZE, "%s", g_settings.get("name").c_str());\r
        }\r
        else\r
        {\r
@@ -1254,10 +1130,10 @@ int main(int argc, char *argv[])
        u16 screenH;\r
        bool fullscreen = false;\r
        \r
-       if(g_screenW != "" && g_screenH != "")\r
+       if(g_settings.get("screenW") != "" && g_settings.get("screenH") != "")\r
        {\r
-               screenW = atoi(g_screenW.c_str());\r
-               screenH = atoi(g_screenH.c_str());\r
+               screenW = atoi(g_settings.get("screenW").c_str());\r
+               screenH = atoi(g_settings.get("screenH").c_str());\r
        }\r
        else\r
        {\r
@@ -1343,7 +1219,7 @@ int main(int argc, char *argv[])
        \r
        device->setResizable(true);\r
 \r
-       if(g_random_input)\r
+       if(g_settings.getBool("random_input"))\r
                g_input = new RandomInputHandler();\r
        else\r
                g_input = new RealInputHandler(device, &receiver);\r
@@ -1443,9 +1319,7 @@ int main(int argc, char *argv[])
        */\r
        SharedPtr<Server> server;\r
        if(hosting){\r
-               server = new Server("../map", g_creative_mode, g_hm_params,\r
-                               g_map_params, g_objectdata_interval,\r
-                               g_active_object_range);\r
+               server = new Server("../map", hm_params, map_params);\r
                server->start(port);\r
        }\r
        \r
@@ -1455,7 +1329,7 @@ int main(int argc, char *argv[])
 \r
        // TODO: Get rid of the g_materials parameter or it's globalness\r
        Client client(device, g_materials,\r
-                       g_client_delete_unused_sectors_timeout,\r
+                       g_settings.getFloat("client_delete_unused_sectors_timeout"),\r
                        playername);\r
        \r
        Address connect_address(0,0,0,0, port);\r
@@ -1648,7 +1522,7 @@ int main(int argc, char *argv[])
                */\r
 \r
                {\r
-                       float fps_max = g_fps_max;\r
+                       float fps_max = g_settings.getFloat("fps_max");\r
                        u32 frametime_min = 1000./fps_max;\r
                        \r
                        if(busytime_u32 < frametime_min)\r
@@ -2326,7 +2200,7 @@ int main(int argc, char *argv[])
        delete g_input;\r
 \r
        /*\r
-       In the end, delete the Irrlicht device.\r
+               In the end, delete the Irrlicht device.\r
        */\r
        device->drop();\r
 \r
index 59ef0ff031bd1db8575fd85d94dab24156a76da2..950e4039f6e3f3b8f14dc3b7bfbddcfb2b4cd37e 100644 (file)
@@ -16,6 +16,9 @@ extern s16 g_viewing_range_nodes;
 //extern s16 g_actual_viewing_range_nodes;
 extern bool g_viewing_range_all;
 
+// Settings
+extern Settings g_settings;
+
 #include <fstream>
 
 // Debug streams
index 35bf8bb4035a34aece61c2282c645b7e56246e50..33f40f064a30d6dfc200650d8f36048626500fcd 100644 (file)
@@ -9,6 +9,7 @@
 #include "client.h"
 #include "filesys.h"
 #include "utility.h"
+#include "voxel.h"
 
 #ifdef _WIN32
        #include <windows.h>
        #define sleep_ms(x) usleep(x*1000)
 #endif
 
+MapBlockPointerCache::MapBlockPointerCache(Map *map)
+{
+       m_map = map;
+       m_map->m_blockcachelock.cacheCreated();
+
+       m_from_cache_count = 0;
+       m_from_map_count = 0;
+}
+
+MapBlockPointerCache::~MapBlockPointerCache()
+{
+       m_map->m_blockcachelock.cacheRemoved();
+
+       dstream<<"MapBlockPointerCache:"
+                       <<" from_cache_count="<<m_from_cache_count
+                       <<" from_map_count="<<m_from_map_count
+                       <<std::endl;
+}
+
+MapBlock * MapBlockPointerCache::getBlockNoCreate(v3s16 p)
+{
+       core::map<v3s16, MapBlock*>::Node *n = NULL;
+       n = m_blocks.find(p);
+       if(n != NULL)
+       {
+               m_from_cache_count++;
+               return n->getValue();
+       }
+       
+       m_from_map_count++;
+       
+       // Throws InvalidPositionException if not found
+       MapBlock *b = m_map->getBlockNoCreate(p);
+       m_blocks[p] = b;
+       return b;
+}
+
+/*
+       Map
+*/
+
 Map::Map(std::ostream &dout):
        m_dout(dout),
        m_camera_position(0,0,0),
@@ -158,33 +200,11 @@ bool Map::isNodeUnderground(v3s16 p)
        }
 }
 
-#ifdef LKJnb
-//TODO: Remove: Not used.
-/*
-       Goes recursively through the neighbours of the node.
-
-       Alters only transparent nodes.
-
-       If the lighting of the neighbour is lower than the lighting of
-       the node was (before changing it to 0 at the step before), the
-       lighting of the neighbour is set to 0 and then the same stuff
-       repeats for the neighbour.
-
-       Some things are made strangely to make it as fast as possible.
-
-       Usage: (for clearing all possible spreaded light of a lamp)
-       NOTE: This is outdated
-               core::list<v3s16> light_sources;
-               core::map<v3s16, MapBlock*> modified_blocks;
-               u8 oldlight = node_at_pos.light;
-               node_at_pos.setLight(0);
-               unLightNeighbors(pos, oldlight, light_sources, modified_blocks);
-*/
-void Map::unLightNeighbors(v3s16 pos, u8 oldlight,
-               core::map<v3s16, bool> & light_sources,
-               core::map<v3s16, MapBlock*>  & modified_blocks)
+#if 0
+void Map::interpolate(v3s16 block,
+               core::map<v3s16, MapBlock*> & modified_blocks)
 {
-       v3s16 dirs[6] = {
+       const v3s16 dirs[6] = {
                v3s16(0,0,1), // back
                v3s16(0,1,0), // top
                v3s16(1,0,0), // right
@@ -192,7 +212,16 @@ void Map::unLightNeighbors(v3s16 pos, u8 oldlight,
                v3s16(0,-1,0), // bottom
                v3s16(-1,0,0), // left
        };
+
+       if(from_nodes.size() == 0)
+               return;
        
+       u32 blockchangecount = 0;
+
+       core::map<v3s16, bool> lighted_nodes;
+       core::map<v3s16, bool>::Iterator j;
+       j = from_nodes.getIterator();
+
        /*
                Initialize block cache
        */
@@ -201,23 +230,22 @@ void Map::unLightNeighbors(v3s16 pos, u8 oldlight,
        // Cache this a bit, too
        bool block_checked_in_modified = false;
        
-       // Loop through 6 neighbors
-       for(u16 i=0; i<6; i++){
-               // Get the position of the neighbor node
-               v3s16 n2pos = pos + dirs[i];
+       for(; j.atEnd() == false; j++)
+       //for(; j != from_nodes.end(); j++)
+       {
+               v3s16 pos = j.getNode()->getKey();
+               //v3s16 pos = *j;
+               //dstream<<"pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
+               v3s16 blockpos = getNodeBlockPos(pos);
                
-               // Get the block where the node is located
-               v3s16 blockpos = getNodeBlockPos(n2pos);
-
                // Only fetch a new block if the block position has changed
                try{
-                       if(block == NULL || blockpos != blockpos_last)
-                       {
+                       if(block == NULL || blockpos != blockpos_last){
                                block = getBlockNoCreate(blockpos);
                                blockpos_last = blockpos;
-                               
+
                                block_checked_in_modified = false;
-                               //blockchangecount++;
+                               blockchangecount++;
                        }
                }
                catch(InvalidPositionException &e)
@@ -227,33 +255,75 @@ void Map::unLightNeighbors(v3s16 pos, u8 oldlight,
 
                if(block->isDummy())
                        continue;
-               
+
                // Calculate relative position in block
-               v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
+               v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
+
                // Get node straight from the block
-               MapNode n2 = block->getNode(relpos);
-               
-               /*
-                       If the neighbor is dimmer than what was specified
-                       as oldlight (the light of the previous node)
-               */
-               if(n2.getLight() < oldlight)
-               {
-                       /*
-                               And the neighbor is transparent and it has some light
-                       */
-                       if(n2.light_propagates() && n2.getLight() != 0)
+               MapNode n = block->getNode(relpos);
+
+               u8 oldlight = n.getLight();
+               u8 newlight = diminish_light(oldlight);
+
+               // Loop through 6 neighbors
+               for(u16 i=0; i<6; i++){
+                       // Get the position of the neighbor node
+                       v3s16 n2pos = pos + dirs[i];
+                       
+                       // Get the block where the node is located
+                       v3s16 blockpos = getNodeBlockPos(n2pos);
+
+                       try
                        {
+                               // Only fetch a new block if the block position has changed
+                               try{
+                                       if(block == NULL || blockpos != blockpos_last){
+                                               block = getBlockNoCreate(blockpos);
+                                               blockpos_last = blockpos;
+
+                                               block_checked_in_modified = false;
+                                               blockchangecount++;
+                                       }
+                               }
+                               catch(InvalidPositionException &e)
+                               {
+                                       continue;
+                               }
+                               
+                               // Calculate relative position in block
+                               v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
+                               // Get node straight from the block
+                               MapNode n2 = block->getNode(relpos);
+                               
+                               bool changed = false;
                                /*
-                                       Set light to 0 and recurse.
+                                       If the neighbor is brighter than the current node,
+                                       add to list (it will light up this node on its turn)
                                */
-                               u8 current_light = n2.getLight();
-                               n2.setLight(0);
-                               block->setNode(relpos, n2);
-                               unLightNeighbors(n2pos, current_light,
-                                               light_sources, modified_blocks);
-                               
-                               if(block_checked_in_modified == false)
+                               if(n2.getLight() > undiminish_light(oldlight))
+                               {
+                                       lighted_nodes.insert(n2pos, true);
+                                       //lighted_nodes.push_back(n2pos);
+                                       changed = true;
+                               }
+                               /*
+                                       If the neighbor is dimmer than how much light this node
+                                       would spread on it, add to list
+                               */
+                               if(n2.getLight() < newlight)
+                               {
+                                       if(n2.light_propagates())
+                                       {
+                                               n2.setLight(newlight);
+                                               block->setNode(relpos, n2);
+                                               lighted_nodes.insert(n2pos, true);
+                                               //lighted_nodes.push_back(n2pos);
+                                               changed = true;
+                                       }
+                               }
+
+                               // Add to modified_blocks
+                               if(changed == true && block_checked_in_modified == false)
                                {
                                        // If the block is not found in modified_blocks, add.
                                        if(modified_blocks.find(blockpos) == NULL)
@@ -263,12 +333,20 @@ void Map::unLightNeighbors(v3s16 pos, u8 oldlight,
                                        block_checked_in_modified = true;
                                }
                        }
-               }
-               else{
-                       //light_sources.push_back(n2pos);
-                       light_sources.insert(n2pos, true);
+                       catch(InvalidPositionException &e)
+                       {
+                               continue;
+                       }
                }
        }
+
+       /*dstream<<"spreadLight(): Changed block "
+                       <<blockchangecount<<" times"
+                       <<" for "<<from_nodes.size()<<" nodes"
+                       <<std::endl;*/
+       
+       if(lighted_nodes.size() > 0)
+               spreadLight(lighted_nodes, modified_blocks);
 }
 #endif
 
@@ -1090,6 +1168,13 @@ void Map::timerUpdate(float dtime)
 
 void Map::deleteSectors(core::list<v2s16> &list, bool only_blocks)
 {
+       /*
+               Wait for caches to be removed before continuing.
+               
+               This disables the existence of caches while locked
+       */
+       SharedPtr<JMutexAutoLock> cachelock(m_blockcachelock.waitCaches());
+
        core::list<v2s16>::Iterator j;
        for(j=list.begin(); j!=list.end(); j++)
        {
@@ -1215,13 +1300,13 @@ ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp):
        
        // Create master heightmap
        ValueGenerator *maxgen =
-                       ValueGenerator::deSerialize(hmp.height_randmax);
+                       ValueGenerator::deSerialize(hmp.randmax);
        ValueGenerator *factorgen =
-                       ValueGenerator::deSerialize(hmp.height_randfactor);
+                       ValueGenerator::deSerialize(hmp.randfactor);
        ValueGenerator *basegen =
-                       ValueGenerator::deSerialize(hmp.height_base);
+                       ValueGenerator::deSerialize(hmp.base);
        m_heightmap = new UnlimitedHeightmap
-                       (hmp.heightmap_blocksize, maxgen, factorgen, basegen);
+                       (hmp.blocksize, maxgen, factorgen, basegen);
        
        // Set map parameters
        m_params = mp;
@@ -1409,6 +1494,9 @@ MapSector * ServerMap::emergeSector(v2s16 p2d)
                                        SECTOR_OBJECT_TREE_1);
                }
        }
+       /*
+               Plant some bushes if sector is pit-like
+       */
        {
                // Pitness usually goes at around -0.5...0.5
                u32 bush_max = 0;
@@ -1429,6 +1517,22 @@ MapSector * ServerMap::emergeSector(v2s16 p2d)
                                        SECTOR_OBJECT_BUSH_1);
                }
        }
+       /*
+               Add ravine (randomly)
+       */
+       {
+               if(rand()%10 == 0)
+               {
+                       s16 s = 6;
+                       s16 x = rand()%(MAP_BLOCKSIZE-s*2-1)+s;
+                       s16 z = rand()%(MAP_BLOCKSIZE-s*2-1)+s;
+                       /*s16 x = 8;
+                       s16 z = 8;*/
+                       s16 y = sector->getGroundHeight(v2s16(x,z))+1;
+                       objects->insert(v3s16(x, y, z),
+                                       SECTOR_OBJECT_RAVINE);
+               }
+       }
 
        /*
                Insert to container
@@ -1533,9 +1637,16 @@ MapBlock * ServerMap::emergeBlock(
        }
 
        // Randomize a bit. This makes dungeons.
-       bool low_block_is_empty = false;
+       /*bool low_block_is_empty = false;
        if(rand() % 4 == 0)
-               low_block_is_empty = true;
+               low_block_is_empty = true;*/
+       
+       s32 ued = 4;
+       bool underground_emptiness[ued*ued*ued];
+       for(s32 i=0; i<ued*ued*ued; i++)
+       {
+               underground_emptiness[i] = ((rand() % 4) == 0);
+       }
        
        // This is the basic material of what the visible flat ground
        // will consist of
@@ -1551,9 +1662,7 @@ MapBlock * ServerMap::emergeBlock(
        {
                //dstream<<"emergeBlock: x0="<<x0<<", z0="<<z0<<std::endl;
                float surface_y_f = sector->getGroundHeight(v2s16(x0,z0));
-
                assert(surface_y_f > GROUNDHEIGHT_VALID_MINVALUE);
-               
                s16 surface_y = surface_y_f;
                //avg_ground_y += surface_y;
                if(surface_y < lowest_ground_y)
@@ -1574,13 +1683,14 @@ MapBlock * ServerMap::emergeBlock(
                else
                        surface_depth = (1.-(slope-min_slope)/max_slope) * min_slope_depth;
 
-               for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++){
+               for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
+               {
                        s16 real_y = block_y * MAP_BLOCKSIZE + y0;
                        MapNode n;
                        /*
                                Calculate lighting
                                
-                               FIXME: If there are some man-made structures above the
+                               NOTE: If there are some man-made structures above the
                                newly created block, they won't be taken into account.
                        */
                        if(real_y > surface_y)
@@ -1589,12 +1699,17 @@ MapBlock * ServerMap::emergeBlock(
                                Calculate material
                        */
                        // If node is very low
-                       if(real_y <= surface_y - 10){
+                       if(real_y <= surface_y - 7){
                                // Create dungeons
-                               if(low_block_is_empty){
+                               if(underground_emptiness[
+                                               ued*ued*(z0*ued/MAP_BLOCKSIZE)
+                                               +ued*(y0*ued/MAP_BLOCKSIZE)
+                                               +(x0*ued/MAP_BLOCKSIZE)])
+                               {
                                        n.d = MATERIAL_AIR;
                                }
-                               else{
+                               else
+                               {
                                        n.d = MATERIAL_STONE;
                                }
                        }
@@ -1603,7 +1718,14 @@ MapBlock * ServerMap::emergeBlock(
                                n.d = MATERIAL_STONE;
                        // If node is at or under heightmap y
                        else if(real_y <= surface_y)
-                               n.d = material;
+                       {
+                               // If under water level, it's mud
+                               if(real_y < WATER_LEVEL)
+                                       n.d = MATERIAL_MUD;
+                               // Else it's the main material
+                               else
+                                       n.d = material;
+                       }
                        // If node is over heightmap y
                        else{
                                // If under water level, it's water
@@ -1628,11 +1750,21 @@ MapBlock * ServerMap::emergeBlock(
        bool is_underground = (block_y+1) * MAP_BLOCKSIZE < lowest_ground_y;
        block->setIsUnderground(is_underground);
 
+       /*
+               Force lighting update if underground.
+               This is needed because of ravines.
+       */
+
+       if(is_underground)
+       {
+               lighting_invalidated_blocks[block->getPos()] = block;
+       }
+       
        /*
                Add some minerals
        */
 
-       if(is_underground && low_block_is_empty == false)
+       if(is_underground)
        {
                s16 underground_level = lowest_ground_y/MAP_BLOCKSIZE - block_y;
                for(s16 i=0; i<underground_level*3; i++)
@@ -1640,9 +1772,6 @@ MapBlock * ServerMap::emergeBlock(
                        if(rand()%2 == 0)
                        {
                                v3s16 cp(
-                                       /*(rand()%(MAP_BLOCKSIZE-4))+2,
-                                       (rand()%(MAP_BLOCKSIZE-4))+2,
-                                       (rand()%(MAP_BLOCKSIZE-4))+2*/
                                        (rand()%(MAP_BLOCKSIZE-2))+1,
                                        (rand()%(MAP_BLOCKSIZE-2))+1,
                                        (rand()%(MAP_BLOCKSIZE-2))+1
@@ -1656,6 +1785,9 @@ MapBlock * ServerMap::emergeBlock(
 
                                for(u16 i=0; i<26; i++)
                                {
+                                       if(!is_ground_material(block->getNode(cp+g_26dirs[i]).d))
+                                               continue;
+
                                        if(rand()%8 == 0)
                                                block->setNode(cp+g_26dirs[i], n);
                                }
@@ -1666,7 +1798,7 @@ MapBlock * ServerMap::emergeBlock(
        /*
                Create a few rats in empty blocks underground
        */
-       if(is_underground && low_block_is_empty == true)
+       /*if(is_underground && low_block_is_empty == true)
        {
                //for(u16 i=0; i<2; i++)
                {
@@ -1674,42 +1806,54 @@ MapBlock * ServerMap::emergeBlock(
                        RatObject *obj = new RatObject(NULL, -1, intToFloat(pos));
                        block->addObject(obj);
                }
-       }
+       }*/
        
        /*
-               TODO: REMOVE
-               DEBUG
-               Add some objects to the block for testing.
+               Add block to sector.
        */
-       /*if(p == v3s16(0,0,0))
-       {
-               //TestObject *obj = new TestObject(NULL, -1, v3f(BS*8,BS*8,BS*8));
-               Test2Object *obj = new Test2Object(NULL, -1, v3f(BS*8,BS*15,BS*8));
-               block->addObject(obj);
-       }*/
+       sector->insertBlock(block);
        
        /*
+               Do some interpolation for dungeons
+       */
+
+#if 0  
        {
-               v3s16 pos(8, 11, 8);
-               SignObject *obj = new SignObject(NULL, -1, intToFloat(pos));
-               obj->setText("Moicka");
-               obj->setYaw(45);
-               block->addObject(obj);
-       }
+       TimeTaker timer("interpolation", g_device);
+       
+       MapVoxelManipulator vmanip(this);
+       
+       v3s16 relpos = block->getPosRelative();
+
+       vmanip.interpolate(VoxelArea(relpos-v3s16(1,1,1),
+                       relpos+v3s16(1,1,1)*(MAP_BLOCKSIZE+1)));
+       /*vmanip.interpolate(VoxelArea(relpos,
+                       relpos+v3s16(1,1,1)*(MAP_BLOCKSIZE-1)));*/
+       
+       core::map<v3s16, MapBlock*> modified_blocks;
+       vmanip.blitBack(modified_blocks);
+       dstream<<"blitBack modified "<<modified_blocks.size()
+                       <<" blocks"<<std::endl;
 
+       // Add modified blocks to changed_blocks and lighting_invalidated_blocks
+       for(core::map<v3s16, MapBlock*>::Iterator
+                       i = modified_blocks.getIterator();
+                       i.atEnd() == false; i++)
        {
-               v3s16 pos(8, 11, 8);
-               RatObject *obj = new RatObject(NULL, -1, intToFloat(pos));
-               block->addObject(obj);
+               MapBlock *block = i.getNode()->getValue();
+
+               changed_blocks.insert(block->getPos(), block);
+               //lighting_invalidated_blocks.insert(block->getPos(), block);
        }
-       */
+
+       }
+#endif
 
        /*
-               Add block to sector.
+               Sector object stuff
        */
-       sector->insertBlock(block);
-       
-       // An y-wise container if changed blocks
+               
+       // An y-wise container of changed blocks
        core::map<s16, MapBlock*> changed_blocks_sector;
 
        /*
@@ -1722,6 +1866,7 @@ MapBlock * ServerMap::emergeBlock(
                        i.atEnd() == false; i++)
        {
                v3s16 p = i.getNode()->getKey();
+               v2s16 p2d(p.X,p.Z);
                u8 d = i.getNode()->getValue();
 
                //v3s16 p = p_sector - v3s16(0, block_y*MAP_BLOCKSIZE, 0);
@@ -1795,6 +1940,66 @@ MapBlock * ServerMap::emergeBlock(
                                objects_to_remove.push_back(p);
                        }
                }
+               else if(d == SECTOR_OBJECT_RAVINE)
+               {
+                       s16 maxdepth = -20;
+                       v3s16 p_min = p + v3s16(-6,maxdepth,-6);
+                       v3s16 p_max = p + v3s16(6,6,6);
+                       if(sector->isValidArea(p_min, p_max,
+                                       &changed_blocks_sector))
+                       {
+                               MapNode n;
+                               n.d = MATERIAL_STONE;
+                               MapNode n2;
+                               n2.d = MATERIAL_AIR;
+                               s16 depth = maxdepth + (rand()%10);
+                               s16 z = 0;
+                               s16 minz = -6 - (-2);
+                               s16 maxz = 6 -1;
+                               for(s16 x=-6; x<=6; x++)
+                               {
+                                       z += -1 + (rand()%3);
+                                       if(z < minz)
+                                               z = minz;
+                                       if(z > maxz)
+                                               z = maxz;
+                                       for(s16 y=depth+(rand()%2); y<=6; y++)
+                                       {
+                                               /*std::cout<<"("<<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
+                                                               <<std::endl;*/
+                                               {
+                                                       v3s16 p2 = p + v3s16(x,y,z-2);
+                                                       if(is_ground_material(sector->getNode(p2).d))
+                                                               sector->setNode(p2, n);
+                                               }
+                                               {
+                                                       v3s16 p2 = p + v3s16(x,y,z-1);
+                                                       if(is_ground_material(sector->getNode(p2).d))
+                                                               sector->setNode(p2, n2);
+                                               }
+                                               {
+                                                       v3s16 p2 = p + v3s16(x,y,z+0);
+                                                       if(is_ground_material(sector->getNode(p2).d))
+                                                               sector->setNode(p2, n2);
+                                               }
+                                               {
+                                                       v3s16 p2 = p + v3s16(x,y,z+1);
+                                                       if(is_ground_material(sector->getNode(p2).d))
+                                                               sector->setNode(p2, n);
+                                               }
+
+                                               //if(sector->getNode(p+v3s16(x,y,z+1)).solidness()==2)
+                                               //if(p.Y+y <= sector->getGroundHeight(p2d+v2s16(x,z-2))+0.5)
+                                       }
+                               }
+                               
+                               objects_to_remove.push_back(p);
+                               
+                               // Lighting has to be recalculated for this one.
+                               sector->getBlocksInArea(p_min, p_max, 
+                                               lighting_invalidated_blocks);
+                       }
+               }
                else
                {
                        dstream<<"ServerMap::emergeBlock(): "
@@ -1807,7 +2012,7 @@ MapBlock * ServerMap::emergeBlock(
                {
                        dstream<<"WARNING: "<<__FUNCTION_NAME
                                        <<": while inserting object "<<(int)d
-                                       <<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
+                                       <<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<"):"
                                        <<" InvalidPositionException.what()="
                                        <<e.what()<<std::endl;
                        // This is not too fatal and seems to happen sometimes.
index 482ab2ac79ef03e547af42d067e29125925d6bc9..eb459fbcaf80421ed5682997080fdfc59fe2db32 100644 (file)
--- a/src/map.h
+++ b/src/map.h
 #include "mapsector.h"
 #include "constants.h"
 
-class InvalidFilenameException : public BaseException
+class Map;
+
+/*
+       A cache for short-term fast access to map data
+
+       NOTE: This doesn't really make anything more efficient
+       NOTE: Use VoxelManipulator, if possible
+       TODO: Get rid of this?
+*/
+class MapBlockPointerCache : public NodeContainer
+{
+public:
+       MapBlockPointerCache(Map *map);
+       ~MapBlockPointerCache();
+
+       virtual u16 nodeContainerId() const
+       {
+               return NODECONTAINER_ID_MAPBLOCKCACHE;
+       }
+
+       MapBlock * getBlockNoCreate(v3s16 p);
+
+       // virtual from NodeContainer
+       bool isValidPosition(v3s16 p)
+       {
+               v3s16 blockpos = getNodeBlockPos(p);
+               MapBlock *blockref;
+               try{
+                       blockref = getBlockNoCreate(blockpos);
+               }
+               catch(InvalidPositionException &e)
+               {
+                       return false;
+               }
+               return true;
+       }
+       
+       // virtual from NodeContainer
+       MapNode getNode(v3s16 p)
+       {
+               v3s16 blockpos = getNodeBlockPos(p);
+               MapBlock * blockref = getBlockNoCreate(blockpos);
+               v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
+
+               return blockref->getNodeNoCheck(relpos);
+       }
+
+       // virtual from NodeContainer
+       void setNode(v3s16 p, MapNode & n)
+       {
+               v3s16 blockpos = getNodeBlockPos(p);
+               MapBlock * block = getBlockNoCreate(blockpos);
+               v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
+               block->setNodeNoCheck(relpos, n);
+               m_modified_blocks[blockpos] = block;
+       }
+
+       core::map<v3s16, MapBlock*> m_modified_blocks;
+       
+private:
+       Map *m_map;
+       core::map<v3s16, MapBlock*> m_blocks;
+
+       u32 m_from_cache_count;
+       u32 m_from_map_count;
+};
+
+class CacheLock
 {
 public:
-       InvalidFilenameException(const char *s):
-               BaseException(s)
-       {}
+       CacheLock()
+       {
+               m_count = 0;
+               m_count_mutex.Init();
+               m_cache_mutex.Init();
+               m_waitcache_mutex.Init();
+       }
+
+       void cacheCreated()
+       {
+               JMutexAutoLock waitcachelock(m_waitcache_mutex);
+               JMutexAutoLock countlock(m_count_mutex);
+
+               // If this is the first cache, grab the cache lock
+               if(m_count == 0)
+                       m_cache_mutex.Lock();
+                       
+               m_count++;
+       }
+
+       void cacheRemoved()
+       {
+               JMutexAutoLock countlock(m_count_mutex);
+
+               assert(m_count > 0);
+
+               m_count--;
+               
+               // If this is the last one, release the cache lock
+               if(m_count == 0)
+                       m_cache_mutex.Unlock();
+       }
+
+       /*
+               This lock should be taken when removing stuff that can be
+               pointed by the cache.
+
+               You'll want to grab this in a SharedPtr.
+       */
+       JMutexAutoLock * waitCaches()
+       {
+               JMutexAutoLock waitcachelock(m_waitcache_mutex);
+               return new JMutexAutoLock(m_cache_mutex);
+       }
+
+private:
+       // Count of existing caches
+       u32 m_count;
+       JMutex m_count_mutex;
+       // This is locked always when there are some caches
+       JMutex m_cache_mutex;
+       // Locked so that when waitCaches() is called, no more caches are created
+       JMutex m_waitcache_mutex;
 };
 
 #define MAPTYPE_BASE 0
@@ -60,6 +177,13 @@ protected:
 public:
 
        v3s16 drawoffset; // for drawbox()
+       
+       /*
+               Used by MapBlockPointerCache.
+
+               waitCaches() can be called to remove all caches before continuing
+       */
+       CacheLock m_blockcachelock;
 
        Map(std::ostream &dout);
        virtual ~Map();
@@ -154,7 +278,7 @@ public:
                MapBlock * blockref = getBlockNoCreate(blockpos);
                v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
 
-               return blockref->getNode(relpos);
+               return blockref->getNodeNoCheck(relpos);
        }
 
        // virtual from NodeContainer
@@ -163,7 +287,7 @@ public:
                v3s16 blockpos = getNodeBlockPos(p);
                MapBlock * blockref = getBlockNoCreate(blockpos);
                v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
-               blockref->setNode(relpos, n);
+               blockref->setNodeNoCheck(relpos, n);
        }
 
        /*MapNode getNodeGenerate(v3s16 p)
@@ -247,15 +371,15 @@ struct HMParams
 {
        HMParams()
        {
-               heightmap_blocksize = 64;
-               height_randmax = "constant 70.0";
-               height_randfactor = "constant 0.6";
-               height_base = "linear 0 80 0";
+               blocksize = 64;
+               randmax = "constant 70.0";
+               randfactor = "constant 0.6";
+               base = "linear 0 80 0";
        }
-       s16 heightmap_blocksize;
-       std::string height_randmax;
-       std::string height_randfactor;
-       std::string height_base;
+       s16 blocksize;
+       std::string randmax;
+       std::string randfactor;
+       std::string base;
 };
 
 // Map parameters
index 60f78b6ffb36103bf0f21a6ff0d861f028d6c3b9..48f8775519fe8e47b713dba47e43beda4a6c9b2e 100644 (file)
@@ -38,7 +38,9 @@ enum
 {
        NODECONTAINER_ID_MAPBLOCK,
        NODECONTAINER_ID_MAPSECTOR,
-       NODECONTAINER_ID_MAP
+       NODECONTAINER_ID_MAP,
+       NODECONTAINER_ID_MAPBLOCKCACHE,
+       NODECONTAINER_ID_VOXELMANIPULATOR,
 };
 
 class NodeContainer
@@ -245,6 +247,35 @@ public:
                setNode(p.X, p.Y, p.Z, n);
        }
 
+       /*
+               Non-checking variants of the above
+       */
+
+       MapNode getNodeNoCheck(s16 x, s16 y, s16 z)
+       {
+               if(data == NULL)
+                       throw InvalidPositionException();
+               return data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x];
+       }
+       
+       MapNode getNodeNoCheck(v3s16 p)
+       {
+               return getNodeNoCheck(p.X, p.Y, p.Z);
+       }
+       
+       void setNodeNoCheck(s16 x, s16 y, s16 z, MapNode & n)
+       {
+               if(data == NULL)
+                       throw InvalidPositionException();
+               data[z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + y*MAP_BLOCKSIZE + x] = n;
+               setChangedFlag();
+       }
+       
+       void setNodeNoCheck(v3s16 p, MapNode & n)
+       {
+               setNodeNoCheck(p.X, p.Y, p.Z, n);
+       }
+
        /*
                These functions consult the parent container if the position
                is not valid on this MapBlock.
index 68e669161c4e9e8e0bb272d6d1c5bdb5ac0a7614..981f36d86ed5055364850dfe9e85e3b40d2818e9 100644 (file)
 
 #define MATERIALS_COUNT 256
 
-// This is completely ignored. It doesn't create faces with anything.
+/*
+       Ignored node.
+
+       param is used for custom information in special containers,
+       like VoxelManipulator.
+
+       Anything that stores MapNodes doesn't have to preserve parameters
+       associated with this material.
+       
+       Doesn't create faces with anything and is considered being
+       out-of-map in the game map.
+*/
 #define MATERIAL_IGNORE 255
-// This is the common material through which the player can walk
-// and which is transparent to light
+#define MATERIAL_IGNORE_DEFAULT_PARAM 0
+
+/*
+       The common material through which the player can walk and which
+       is transparent to light
+*/
 #define MATERIAL_AIR 254
 
 /*
@@ -63,6 +78,8 @@ enum Material
        MATERIAL_GRASS_FOOTSTEPS,
        
        MATERIAL_MESE,
+
+       MATERIAL_MUD,
        
        // This is set to the number of the actual values in this enum
        USEFUL_MATERIAL_COUNT
@@ -126,6 +143,21 @@ inline u8 face_materials(u8 m1, u8 m2)
                return 2;
 }
 
+/*
+       Returns true for materials that form the base ground that
+       follows the main heightmap
+*/
+inline bool is_ground_material(u8 m)
+{
+       return(
+               m == MATERIAL_STONE ||
+               m == MATERIAL_GRASS ||
+               m == MATERIAL_GRASS_FOOTSTEPS ||
+               m == MATERIAL_MESE ||
+               m == MATERIAL_MUD
+       );
+}
+
 struct MapNode
 {
        //TODO: block type to differ from material
@@ -133,9 +165,6 @@ struct MapNode
        // block type
        u8 d;
 
-       // Removed because light is now stored in param for air
-       // f32 light;
-
        /*
                Misc parameter. Initialized to 0.
                - For light_propagates() blocks, this is light intensity,
@@ -155,6 +184,11 @@ struct MapNode
                param = a_param;
        }
 
+       bool operator==(const MapNode &other)
+       {
+               return (d == other.d && param == other.param);
+       }
+
        bool light_propagates()
        {
                return light_propagates_material(d);
index 196a129c3046d0f10a27528d77a84ce3b1c8889a..de8cab536d1917ac2680b2527932fcd611346ffa 100644 (file)
@@ -20,6 +20,7 @@
 #define SECTOR_OBJECT_TEST 0
 #define SECTOR_OBJECT_TREE_1 1
 #define SECTOR_OBJECT_BUSH_1 2
+#define SECTOR_OBJECT_RAVINE 3
 
 #define MAPSECTOR_FIXEDHEIGHTMAPS_MAXCOUNT 4
 
index 83d43599ff1447df47c194368553274adb8371f3..e17e21d324c4ac7ea8f171feb6331d10cc107819 100644 (file)
@@ -178,7 +178,10 @@ void * EmergeThread::Thread()
                                modified_blocks.insert(block->getPos(), block);
                        }
                        
-                       //TimeTaker timer("** updateLighting", g_device);
+                       /*dstream<<"lighting "<<lighting_invalidated_blocks.size()
+                                       <<" blocks"<<std::endl;
+                       TimeTaker timer("** updateLighting", g_device);*/
+                       
                        // Update lighting without locking the environment mutex,
                        // add modified blocks to changed blocks
                        map.updateLighting(lighting_invalidated_blocks, modified_blocks);
@@ -222,11 +225,11 @@ void * EmergeThread::Thread()
                                client->SetBlocksNotSent(modified_blocks);
                        }
                        
-                       if(q->peer_ids.find(client->peer_id) != NULL)
+                       /*if(q->peer_ids.find(client->peer_id) != NULL)
                        {
                                // Decrement emerge queue count of client
                                client->BlockEmerged();
-                       }
+                       }*/
                }
                
        }
@@ -246,282 +249,6 @@ void * EmergeThread::Thread()
        return NULL;
 }
 
-#if 0
-void RemoteClient::SendBlocks(Server *server, float dtime)
-{
-       DSTACK(__FUNCTION_NAME);
-       
-       /*
-               Find what blocks to send to the client next, and send them.
-
-               Throttling is based on limiting the amount of blocks "flying"
-               at a given time.
-       */
-
-       // Can't send anything without knowing version
-       if(serialization_version == SER_FMT_VER_INVALID)
-       {
-               dstream<<"RemoteClient::SendBlocks(): Not sending, no version."
-                               <<std::endl;
-               return;
-       }
-
-       {
-               JMutexAutoLock lock(m_blocks_sending_mutex);
-               
-               if(m_blocks_sending.size() >= MAX_SIMULTANEOUS_BLOCK_SENDS)
-               {
-                       //dstream<<"Not sending any blocks, Queue full."<<std::endl;
-                       return;
-               }
-       }
-
-       Player *player = server->m_env.getPlayer(peer_id);
-
-       v3f playerpos = player->getPosition();
-       v3f playerspeed = player->getSpeed();
-
-       v3s16 center_nodepos = floatToInt(playerpos);
-
-       v3s16 center = getNodeBlockPos(center_nodepos);
-
-       /*
-               Get the starting value of the block finder radius.
-       */
-       s16 last_nearest_unsent_d;
-       s16 d_start;
-       {
-               JMutexAutoLock lock(m_blocks_sent_mutex);
-               
-               if(m_last_center != center)
-               {
-                       m_nearest_unsent_d = 0;
-                       m_last_center = center;
-               }
-
-               static float reset_counter = 0;
-               reset_counter += dtime;
-               if(reset_counter > 5.0)
-               {
-                       reset_counter = 0;
-                       m_nearest_unsent_d = 0;
-               }
-
-               last_nearest_unsent_d = m_nearest_unsent_d;
-               
-               d_start = m_nearest_unsent_d;
-       }
-
-       u16 maximum_simultaneous_block_sends = MAX_SIMULTANEOUS_BLOCK_SENDS;
-
-       {
-               SharedPtr<JMutexAutoLock> lock(m_time_from_building.getLock());
-               m_time_from_building.m_value += dtime;
-               /*
-                       Check the time from last addNode/removeNode.
-                       Decrease send rate if player is building stuff.
-               */
-               if(m_time_from_building.m_value
-                               < FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING)
-               {
-                       maximum_simultaneous_block_sends
-                               = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
-               }
-       }
-
-       // Serialization version used
-       //u8 ser_version = serialization_version;
-
-       //bool has_incomplete_blocks = false;
-       
-       /*
-               TODO: Get this from somewhere
-       */
-       //s16 d_max = 7;
-       s16 d_max = 8;
-
-       //TODO: Get this from somewhere (probably a bigger value)
-       s16 d_max_gen = 5;
-       
-       //dstream<<"Starting from "<<d_start<<std::endl;
-
-       for(s16 d = d_start; d <= d_max; d++)
-       {
-               //dstream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
-               
-               //if(has_incomplete_blocks == false)
-               {
-                       JMutexAutoLock lock(m_blocks_sent_mutex);
-                       /*
-                               If m_nearest_unsent_d was changed by the EmergeThread
-                               (it can change it to 0 through SetBlockNotSent),
-                               update our d to it.
-                               Else update m_nearest_unsent_d
-                       */
-                       if(m_nearest_unsent_d != last_nearest_unsent_d)
-                       {
-                               d = m_nearest_unsent_d;
-                       }
-                       else
-                       {
-                               m_nearest_unsent_d = d;
-                       }
-                       last_nearest_unsent_d = m_nearest_unsent_d;
-               }
-
-               /*
-                       Get the border/face dot coordinates of a "d-radiused"
-                       box
-               */
-               core::list<v3s16> list;
-               getFacePositions(list, d);
-               
-               core::list<v3s16>::Iterator li;
-               for(li=list.begin(); li!=list.end(); li++)
-               {
-                       v3s16 p = *li + center;
-                       
-                       /*
-                               Send throttling
-                               - Don't allow too many simultaneous transfers
-
-                               Also, don't send blocks that are already flying.
-                       */
-                       {
-                               JMutexAutoLock lock(m_blocks_sending_mutex);
-                               
-                               if(m_blocks_sending.size()
-                                               >= maximum_simultaneous_block_sends)
-                               {
-                                       /*dstream<<"Not sending more blocks. Queue full. "
-                                                       <<m_blocks_sending.size()
-                                                       <<std::endl;*/
-                                       return;
-                               }
-
-                               if(m_blocks_sending.find(p) != NULL)
-                                       continue;
-                       }
-                       
-                       /*
-                               Do not go over-limit
-                       */
-                       if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
-                       || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
-                       || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
-                       || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
-                       || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
-                       || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
-                               continue;
-
-                       bool generate = d <= d_max_gen;
-               
-                       // Limit the generating area vertically to half
-                       if(abs(p.Y - center.Y) > d_max_gen / 2)
-                               generate = false;
-                       
-                       /*
-                               Don't send already sent blocks
-                       */
-                       {
-                               JMutexAutoLock lock(m_blocks_sent_mutex);
-                               
-                               if(m_blocks_sent.find(p) != NULL)
-                                       continue;
-                       }
-                                       
-                       /*
-                               Check if map has this block
-                       */
-                       MapBlock *block = NULL;
-                       try
-                       {
-                               block = server->m_env.getMap().getBlockNoCreate(p);
-                       }
-                       catch(InvalidPositionException &e)
-                       {
-                       }
-                       
-                       bool surely_not_found_on_disk = false;
-                       if(block != NULL)
-                       {
-                               /*if(block->isIncomplete())
-                               {
-                                       has_incomplete_blocks = true;
-                                       continue;
-                               }*/
-
-                               if(block->isDummy())
-                               {
-                                       surely_not_found_on_disk = true;
-                               }
-                       }
-
-                       /*
-                               If block has been marked to not exist on disk (dummy)
-                               and generating new ones is not wanted, skip block. TODO
-                       */
-                       if(generate == false && surely_not_found_on_disk == true)
-                       {
-                               // get next one.
-                               continue;
-                       }
-
-                       /*
-                               Add inexistent block to emerge queue.
-                       */
-                       if(block == NULL || surely_not_found_on_disk)
-                       {
-                               // Block not found.
-                               SharedPtr<JMutexAutoLock> lock
-                                               (m_num_blocks_in_emerge_queue.getLock());
-                               
-                               //TODO: Get value from somewhere
-                               //TODO: Balance between clients
-                               //if(server->m_emerge_queue.size() < 1)
-
-                               // Allow only one block in emerge queue
-                               if(m_num_blocks_in_emerge_queue.m_value == 0)
-                               {
-                                       // Add it to the emerge queue and trigger the thread
-                                       
-                                       u8 flags = 0;
-                                       if(generate == false)
-                                               flags |= TOSERVER_GETBLOCK_FLAG_OPTIONAL;
-                                       
-                                       {
-                                               m_num_blocks_in_emerge_queue.m_value++;
-                                       }
-
-                                       server->m_emerge_queue.addBlock(peer_id, p, flags);
-                                       server->m_emergethread.trigger();
-                               }
-                               
-                               // get next one.
-                               continue;
-                       }
-
-                       /*
-                               Send block
-                       */
-                       
-                       /*dstream<<"RemoteClient::SendBlocks(): d="<<d<<", p="
-                               <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
-                               <<" sending queue size: "<<m_blocks_sending.size()<<std::endl;*/
-
-                       server->SendBlockNoLock(peer_id, block, serialization_version);
-                       
-                       /*
-                               Add to history
-                       */
-                       SentBlock(p);
-               }
-       }
-
-       // Don't add anything here. The loop breaks by returning.
-}
-#endif // backup of SendBlocks
-
 void RemoteClient::GetNextBlocks(Server *server, float dtime,
                core::array<PrioritySortedBlockTransfer> &dest)
 {
@@ -531,7 +258,8 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
        {
                JMutexAutoLock lock(m_blocks_sending_mutex);
                
-               if(m_blocks_sending.size() >= MAX_SIMULTANEOUS_BLOCK_SENDS)
+               if(m_blocks_sending.size() >= g_settings.getU16
+                               ("max_simultaneous_block_sends_per_client"))
                {
                        //dstream<<"Not sending any blocks, Queue full."<<std::endl;
                        return;
@@ -574,15 +302,17 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                d_start = m_nearest_unsent_d;
        }
 
-       u16 maximum_simultaneous_block_sends = MAX_SIMULTANEOUS_BLOCK_SENDS;
+       u16 maximum_simultaneous_block_sends = g_settings.getU16
+                       ("max_simultaneous_block_sends_per_client");
 
+       /*
+               Check the time from last addNode/removeNode.
+               
+               Decrease send rate if player is building stuff.
+       */
        {
                SharedPtr<JMutexAutoLock> lock(m_time_from_building.getLock());
                m_time_from_building.m_value += dtime;
-               /*
-                       Check the time from last addNode/removeNode.
-                       Decrease send rate if player is building stuff.
-               */
                if(m_time_from_building.m_value
                                < FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING)
                {
@@ -646,9 +376,11 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                        /*
                                Send throttling
                                - Don't allow too many simultaneous transfers
+                               - EXCEPT when the blocks are very close
 
                                Also, don't send blocks that are already flying.
                        */
+                       if(d >= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
                        {
                                JMutexAutoLock lock(m_blocks_sending_mutex);
                                
@@ -722,7 +454,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
 
                        /*
                                If block has been marked to not exist on disk (dummy)
-                               and generating new ones is not wanted, skip block. TODO
+                               and generating new ones is not wanted, skip block.
                        */
                        if(generate == false && surely_not_found_on_disk == true)
                        {
@@ -735,16 +467,12 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                        */
                        if(block == NULL || surely_not_found_on_disk)
                        {
-                               // Block not found.
-                               SharedPtr<JMutexAutoLock> lock
-                                               (m_num_blocks_in_emerge_queue.getLock());
+                               /*SharedPtr<JMutexAutoLock> lock
+                                               (m_num_blocks_in_emerge_queue.getLock());*/
                                
                                //TODO: Get value from somewhere
-                               //TODO: Balance between clients
-                               //if(server->m_emerge_queue.size() < 1)
-
                                // Allow only one block in emerge queue
-                               if(m_num_blocks_in_emerge_queue.m_value == 0)
+                               if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
                                {
                                        // Add it to the emerge queue and trigger the thread
                                        
@@ -752,10 +480,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                                        if(generate == false)
                                                flags |= TOSERVER_GETBLOCK_FLAG_OPTIONAL;
                                        
-                                       {
-                                               m_num_blocks_in_emerge_queue.m_value++;
-                                       }
-
                                        server->m_emerge_queue.addBlock(peer_id, p, flags);
                                        server->m_emergethread.trigger();
                                }
@@ -880,7 +604,7 @@ void RemoteClient::SendObjectData(
        v3s16 center = getNodeBlockPos(center_nodepos);
 
        //s16 d_max = ACTIVE_OBJECT_D_BLOCKS;
-       s16 d_max = server->m_active_object_range;
+       s16 d_max = g_settings.getS16("active_object_range");
        
        // Number of blocks whose objects were written to bos
        u16 blockcount = 0;
@@ -956,9 +680,9 @@ void RemoteClient::SendObjectData(
                                // Fetch the block only if it is on disk.
                                
                                // Grab and increment counter
-                               SharedPtr<JMutexAutoLock> lock
+                               /*SharedPtr<JMutexAutoLock> lock
                                                (m_num_blocks_in_emerge_queue.getLock());
-                               m_num_blocks_in_emerge_queue.m_value++;
+                               m_num_blocks_in_emerge_queue.m_value++;*/
                                
                                // Add to queue as an anonymous fetch from disk
                                u8 flags = TOSERVER_GETBLOCK_FLAG_OPTIONAL;
@@ -1072,12 +796,12 @@ void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
        }
 }
 
-void RemoteClient::BlockEmerged()
+/*void RemoteClient::BlockEmerged()
 {
        SharedPtr<JMutexAutoLock> lock(m_num_blocks_in_emerge_queue.getLock());
        assert(m_num_blocks_in_emerge_queue.m_value > 0);
        m_num_blocks_in_emerge_queue.m_value--;
-}
+}*/
 
 /*void RemoteClient::RunSendingTimeouts(float dtime, float timeout)
 {
@@ -1145,19 +869,13 @@ u32 PIChecksum(core::list<PlayerInfo> &l)
 
 Server::Server(
                std::string mapsavedir,
-               bool creative_mode,
                HMParams hm_params,
-               MapParams map_params,
-               float objectdata_interval,
-               u16 active_object_range
+               MapParams map_params
        ):
        m_env(new ServerMap(mapsavedir, hm_params, map_params), dout_server),
        m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
        m_thread(this),
-       m_emergethread(this),
-       m_creative_mode(creative_mode),
-       m_objectdata_interval(objectdata_interval),
-       m_active_object_range(active_object_range)
+       m_emergethread(this)
 {
        m_env_mutex.Init();
        m_con_mutex.Init();
@@ -1196,7 +914,7 @@ void Server::start(unsigned short port)
        m_thread.stop();
        
        // Initialize connection
-       m_con.setTimeoutMs(50);
+       m_con.setTimeoutMs(30);
        m_con.Serve(port);
 
        // Start thread
@@ -1287,7 +1005,7 @@ void Server::AsyncRunStep()
 
        // Run time- and client- related stuff
        // NOTE: If you intend to add something here, check that it
-       // doesn't fit in RemoteClient::SendBlocks for example.
+       // doesn't fit in RemoteClient::GetNextBlocks for example.
        /*{
                // Clients are behind connection lock
                JMutexAutoLock lock(m_con_mutex);
@@ -1309,7 +1027,7 @@ void Server::AsyncRunStep()
        {
                static float counter = 0.0;
                counter += dtime;
-               if(counter >= m_objectdata_interval)
+               if(counter >= g_settings.getFloat("objectdata_interval"))
                {
                        JMutexAutoLock lock1(m_env_mutex);
                        JMutexAutoLock lock2(m_con_mutex);
@@ -1318,9 +1036,22 @@ void Server::AsyncRunStep()
                        counter = 0.0;
                }
        }
+       
+       // Trigger emergethread (it gets somehow gets to a
+       // non-triggered but bysy state sometimes)
+       {
+               static float counter = 0.0;
+               counter += dtime;
+               if(counter >= 2.0)
+               {
+                       counter = 0.0;
+                       
+                       m_emergethread.trigger();
+               }
+       }
 
+       // Save map
        {
-               // Save map
                static float counter = 0.0;
                counter += dtime;
                if(counter >= SERVER_MAP_SAVE_INTERVAL)
@@ -1619,7 +1350,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                // Left click
                if(button == 0)
                {
-                       if(m_creative_mode == false)
+                       if(g_settings.getBool("creative_mode") == false)
                        {
                        
                                // Skip if inventory has no free space
@@ -1684,8 +1415,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                {
                                        return;
                                }
-                               // Otherwise remove it
-                               m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
                        }
                        catch(InvalidPositionException &e)
                        {
@@ -1707,7 +1436,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        // Send as reliable
                        m_con.SendToAll(0, reply, true);
                        
-                       if(m_creative_mode == false)
+                       if(g_settings.getBool("creative_mode") == false)
                        {
                                // Add to inventory and send inventory
                                InventoryItem *item = new MaterialItem(material, 1);
@@ -1715,6 +1444,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                SendInventory(player->peer_id);
                        }
 
+                       /*
+                               Remove the node
+                               (this takes some time so it is done after the quick stuff)
+                       */
+                       m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
+
                } // button == 0
                /*
                        Right button places blocks and stuff
@@ -1744,9 +1479,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                        MapNode n2 = m_env.getMap().getNode(p_over);
                                        if(n2.d != MATERIAL_AIR)
                                                return;
-
-                                       core::map<v3s16, MapBlock*> modified_blocks;
-                                       m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
                                }
                                catch(InvalidPositionException &e)
                                {
@@ -1758,7 +1490,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                // Reset build time counter
                                getClient(peer->id)->m_time_from_building.set(0.0);
                                
-                               if(m_creative_mode == false)
+                               if(g_settings.getBool("creative_mode") == false)
                                {
                                        // Remove from inventory and send inventory
                                        if(mitem->getCount() == 1)
@@ -1779,6 +1511,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                n.serialize(&reply[8], peer_ser_ver);
                                // Send as reliable
                                m_con.SendToAll(0, reply, true);
+                               
+                               /*
+                                       Add node.
+
+                                       This takes some time so it is done after the quick stuff
+                               */
+                               core::map<v3s16, MapBlock*> modified_blocks;
+                               m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
                        }
                        /*
                                Handle block object items
@@ -1828,7 +1568,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 
                                //dout_server<<"Placed object"<<std::endl;
 
-                               if(m_creative_mode == false)
+                               if(g_settings.getBool("creative_mode") == false)
                                {
                                        // Remove from inventory and send inventory
                                        player->inventory.deleteItem(item_i);
@@ -2168,7 +1908,7 @@ void Server::peerAdded(con::Peer *peer)
                        Add stuff to inventory
                */
                
-               if(m_creative_mode)
+               if(g_settings.getBool("creative_mode"))
                {
                        // Give all materials
                        assert(USEFUL_MATERIAL_COUNT <= PLAYER_INVENTORY_SIZE);
@@ -2327,35 +2067,6 @@ void Server::SendInventory(u16 peer_id)
        m_con.Send(peer_id, 0, data, true);
 }
 
-#if 0
-void Server::SendBlocks(float dtime)
-{
-       DSTACK(__FUNCTION_NAME);
-       //dstream<<"Server::SendBlocks(): BEGIN"<<std::endl;
-
-       JMutexAutoLock envlock(m_env_mutex);
-       JMutexAutoLock conlock(m_con_mutex);
-
-       for(core::map<u16, RemoteClient*>::Iterator
-               i = m_clients.getIterator();
-               i.atEnd() == false; i++)
-       {
-               RemoteClient *client = i.getNode()->getValue();
-               assert(client->peer_id == i.getNode()->getKey());
-               
-               if(client->serialization_version == SER_FMT_VER_INVALID)
-                       continue;
-
-               //dstream<<"Server::SendBlocks(): sending blocks for client "<<client->peer_id<<std::endl;
-               
-               //u16 peer_id = client->peer_id;
-               client->SendBlocks(this, dtime);
-       }
-
-       //dstream<<"Server::SendBlocks(): END"<<std::endl;
-}
-#endif
-
 void Server::SendBlocks(float dtime)
 {
        DSTACK(__FUNCTION_NAME);
@@ -2390,8 +2101,9 @@ void Server::SendBlocks(float dtime)
 
        for(u32 i=0; i<queue.size(); i++)
        {
-               //TODO: Calculate value dynamically
-               if(total_sending >= MAX_SIMULTANEOUS_BLOCK_SENDS_SERVER_TOTAL)
+               //TODO: Calculate limit dynamically
+               if(total_sending >= g_settings.getS32
+                               ("max_simultaneous_block_sends_server_total"))
                        break;
                
                PrioritySortedBlockTransfer q = queue[i];
index 8e2e0562603846964c971e3f807ee63b66efb7f6..79cdf052d6fd04052242e8cce58794c3f6249d1a 100644 (file)
@@ -102,6 +102,23 @@ public:
                JMutexAutoLock lock(m_mutex);
                return m_queue.size();
        }
+       
+       u32 peerItemCount(u16 peer_id)
+       {
+               JMutexAutoLock lock(m_mutex);
+
+               u32 count = 0;
+
+               core::list<QueuedBlockEmerge*>::Iterator i;
+               for(i=m_queue.begin(); i!=m_queue.end(); i++)
+               {
+                       QueuedBlockEmerge *q = *i;
+                       if(q->peer_ids.find(peer_id) != NULL)
+                               count++;
+               }
+
+               return count;
+       }
 
 private:
        core::list<QueuedBlockEmerge*> m_queue;
@@ -237,8 +254,8 @@ public:
        u8 pending_serialization_version;
 
        RemoteClient():
-               m_time_from_building(0.0),
-               m_num_blocks_in_emerge_queue(0)
+               m_time_from_building(0.0)
+               //m_num_blocks_in_emerge_queue(0)
        {
                peer_id = 0;
                serialization_version = SER_FMT_VER_INVALID;
@@ -276,7 +293,7 @@ public:
        void SetBlockNotSent(v3s16 p);
        void SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks);
 
-       void BlockEmerged();
+       //void BlockEmerged();
 
        /*bool IsSendingBlock(v3s16 p)
        {
@@ -300,8 +317,8 @@ public:
                JMutexAutoLock l2(m_blocks_sent_mutex);
                JMutexAutoLock l3(m_blocks_sending_mutex);
                o<<"RemoteClient "<<peer_id<<": "
-                               <<"m_num_blocks_in_emerge_queue="
-                               <<m_num_blocks_in_emerge_queue.get()
+                               /*<<"m_num_blocks_in_emerge_queue="
+                               <<m_num_blocks_in_emerge_queue.get()*/
                                <<", m_blocks_sent.size()="<<m_blocks_sent.size()
                                <<", m_blocks_sending.size()="<<m_blocks_sending.size()
                                <<", m_nearest_unsent_d="<<m_nearest_unsent_d
@@ -321,10 +338,11 @@ private:
        */
        
        //TODO: core::map<v3s16, MapBlock*> m_active_blocks
+       //NOTE: Not here, it should be server-wide!
 
        // Number of blocks in the emerge queue that have this client as
        // a receiver. Used for throttling network usage.
-       MutexedVariable<s16> m_num_blocks_in_emerge_queue;
+       //MutexedVariable<s16> m_num_blocks_in_emerge_queue;
 
        /*
                Blocks that have been sent to client.
@@ -367,17 +385,17 @@ public:
                NOTE: Every public method should be thread-safe
        */
        Server(
-                       std::string mapsavedir,
-                       bool creative_mode,
-                       HMParams hm_params,
-                       MapParams map_params,
-                       float objectdata_inverval,
-                       u16 active_object_range
-               );
+               std::string mapsavedir,
+               HMParams hm_params,
+               MapParams map_params
+       );
        ~Server();
        void start(unsigned short port);
        void stop();
+       // This is mainly a way to pass the time to the server.
+       // Actual processing is done in an another thread.
        void step(float dtime);
+       // This is run by ServerThread and does the actual processing
        void AsyncRunStep();
        void Receive();
        void ProcessData(u8 *data, u32 datasize, u16 peer_id);
@@ -387,7 +405,6 @@ public:
 
        // Environment and Connection must be locked when called
        void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver);
-       //void SendBlock(u16 peer_id, MapBlock *block, u8 ver);
        //TODO: Sending of many blocks in a single packet
        
        // Environment and Connection must be locked when called
@@ -431,11 +448,6 @@ private:
 
        BlockEmergeQueue m_emerge_queue;
        
-       // Settings
-       bool m_creative_mode;
-       float m_objectdata_interval;
-       u16 m_active_object_range;
-
        friend class EmergeThread;
        friend class RemoteClient;
 };
index 91b2ef73a717ecf78a522177b5a38ebf9be2869a..88ba78c6ad0c601dde7ca195e1a9494161e0e9b2 100644 (file)
@@ -164,7 +164,9 @@ void UDPSocket::Bind(unsigned short port)
 
     if(bind(m_handle, (const sockaddr*)&address, sizeof(sockaddr_in)) < 0)
     {
+#ifndef DISABLE_ERRNO
                dstream<<(int)m_handle<<": Bind failed: "<<strerror(errno)<<std::endl;
+#endif
                throw SocketException("Failed to bind socket");
     }
 }
@@ -291,7 +293,9 @@ bool UDPSocket::WaitData(int timeout_ms)
        }
        else if(result < 0){
                // Error
+#ifndef DISABLE_ERRNO
                dstream<<(int)m_handle<<": Select failed: "<<strerror(errno)<<std::endl;
+#endif
 #ifdef _WIN32
                dstream<<(int)m_handle<<": WSAGetLastError()="<<WSAGetLastError()<<std::endl;
 #endif
index 8cdd84426855f6539cdd5af14ae1c2ab674022d6..ce00306a634e93ab2162b59260f3247eccacb42b 100644 (file)
@@ -1,6 +1,5 @@
 #include "test.h"
 #include "common_irrlicht.h"
-
 #include "debug.h"
 #include "map.h"
 #include "player.h"
@@ -10,6 +9,7 @@
 #include "connection.h"
 #include "utility.h"
 #include "serialization.h"
+#include "voxel.h"
 #include <sstream>
 
 #ifdef _WIN32
@@ -125,6 +125,45 @@ struct TestMapNode
        }
 };
 
+struct TestVoxelManipulator
+{
+       void Run()
+       {
+               VoxelArea a(v3s16(-1,-1,-1), v3s16(1,1,1));
+               assert(a.index(0,0,0) == 1*3*3 + 1*3 + 1);
+               assert(a.index(-1,-1,-1) == 0);
+
+               VoxelManipulator v;
+
+               v.print(dstream);
+
+               dstream<<"*** Setting (-1,0,-1)=2 ***"<<std::endl;
+
+               //v[v3s16(-1,0,-1)] = MapNode(2);
+               v[v3s16(-1,0,-1)].d = 2;
+
+               v.print(dstream);
+
+               assert(v[v3s16(-1,0,-1)].d == 2);
+
+               dstream<<"*** Reading from inexistent (0,0,-1) ***"<<std::endl;
+
+               assert(v[v3s16(0,0,-1)].d == MATERIAL_IGNORE);
+
+               v.print(dstream);
+
+               dstream<<"*** Adding area ***"<<std::endl;
+
+               v.addArea(a);
+               
+               v.print(dstream);
+
+               assert(v[v3s16(-1,0,-1)].d == 2);
+               assert(v[v3s16(0,1,1)].d == MATERIAL_IGNORE);
+               
+       }
+};
+
 struct TestMapBlock
 {
        class TC : public NodeContainer
@@ -906,6 +945,7 @@ void run_tests()
        TEST(TestUtilities);
        TEST(TestCompress);
        TEST(TestMapNode);
+       TEST(TestVoxelManipulator);
        TEST(TestMapBlock);
        TEST(TestMapSector);
        TEST(TestHeightmap);
index e6a09547bc99f4604d879e5195d3ef3799f4b683..dabcce87cfd80f0f162dca388de21c4299b298d2 100644 (file)
@@ -8,8 +8,11 @@
 #include "common_irrlicht.h"
 #include "debug.h"
 #include "strfnd.h"
+#include "exceptions.h"
 #include <iostream>
+#include <fstream>
 #include <string>
+#include <sstream>
 
 extern const v3s16 g_26dirs[26];
 
@@ -613,5 +616,157 @@ inline s32 stoi(std::string s, s32 min, s32 max)
        return i;
 }
 
+inline s32 stoi(std::string s)
+{
+       return atoi(s.c_str());
+}
+
+/*
+       Config stuff
+*/
+
+class Settings
+{
+public:
+
+       // Returns false on EOF
+       bool parseConfigObject(std::istream &is)
+       {
+               if(is.eof())
+                       return false;
+               
+               // NOTE: This function will be expanded to allow multi-line settings
+               std::string line;
+               std::getline(is, line);
+               //dstream<<"got line: \""<<line<<"\""<<std::endl;
+
+               std::string trimmedline = trim(line);
+               
+               // Ignore comments
+               if(trimmedline[0] == '#')
+                       return true;
+
+               //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
+
+               Strfnd sf(trim(line));
+
+               std::string name = sf.next("=");
+               name = trim(name);
+
+               if(name == "")
+                       return true;
+               
+               std::string value = sf.next("\n");
+               value = trim(value);
+
+               dstream<<"Config name=\""<<name<<"\" value=\""
+                               <<value<<"\""<<std::endl;
+               
+               m_settings[name] = value;
+               
+               return true;
+       }
+
+       // Returns true on success
+       bool readConfigFile(const char *filename)
+       {
+               std::ifstream is(filename);
+               if(is.good() == false)
+               {
+                       dstream<<"Error opening configuration file: "
+                                       <<filename<<std::endl;
+                       return false;
+               }
+
+               dstream<<"Parsing configuration file: "
+                               <<filename<<std::endl;
+                               
+               while(parseConfigObject(is));
+               
+               return true;
+       }
+
+       void set(std::string name, std::string value)
+       {
+               m_settings[name] = value;
+       }
+
+       std::string get(std::string name)
+       {
+               core::map<std::string, std::string>::Node *n;
+               n = m_settings.find(name);
+               if(n == NULL)
+                       throw SettingNotFoundException("Setting not found");
+
+               return n->getValue();
+       }
+
+       bool getBool(std::string name)
+       {
+               return is_yes(get(name));
+       }
+       
+       // Asks if empty
+       bool getBoolAsk(std::string name, std::string question, bool def)
+       {
+               std::string s = get(name);
+               if(s != "")
+                       return is_yes(s);
+               
+               char templine[10];
+               std::cout<<question<<" [y/N]: ";
+               std::cin.getline(templine, 10);
+               s = templine;
+
+               if(s == "")
+                       return def;
+
+               return is_yes(s);
+       }
+
+       float getFloat(std::string name)
+       {
+               float f;
+               std::istringstream vis(get(name));
+               vis>>f;
+               return f;
+       }
+
+       u16 getU16(std::string name)
+       {
+               return stoi(get(name), 0, 65535);
+       }
+
+       u16 getU16Ask(std::string name, std::string question, u16 def)
+       {
+               std::string s = get(name);
+               if(s != "")
+                       return stoi(s, 0, 65535);
+               
+               char templine[10];
+               std::cout<<question<<" ["<<def<<"]: ";
+               std::cin.getline(templine, 10);
+               s = templine;
+
+               if(s == "")
+                       return def;
+
+               return stoi(s, 0, 65535);
+       }
+
+       s16 getS16(std::string name)
+       {
+               return stoi(get(name), -32768, 32767);
+       }
+
+       s32 getS32(std::string name)
+       {
+               return stoi(get(name));
+       }
+
+private:
+       core::map<std::string, std::string> m_settings;
+};
+
 #endif