minecraft-style water done (but no texture animation or sound)
authorPerttu Ahola <celeron55@gmail.com>
Mon, 17 Jan 2011 19:15:31 +0000 (21:15 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Mon, 17 Jan 2011 19:15:31 +0000 (21:15 +0200)
13 files changed:
src/constants.h
src/defaultsettings.cpp
src/light.h
src/main.cpp
src/map.cpp
src/map.h
src/mapblock.cpp
src/mapblock.h
src/mapnode.cpp
src/mapnode.h
src/server.cpp
src/server.h
src/utility.h

index fc800760244db428918ec0326fa83a3a7bdafeb1..3cb2850659571061f91bcfaf6ddc57d6f904843b 100644 (file)
@@ -97,7 +97,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 */
 #define MAX_OBJECTDATA_SIZE 450
 
-#define WATER_LEVEL (0)
+/*
+       This is good to be a bit different than 0 so that water level
+       is not between to MapBlocks
+*/
+#define WATER_LEVEL 3
 
 // Length of cracking animation in count of images
 #define CRACK_ANIMATION_LENGTH 5
index b7b7013d1f2c4fa29e8ace9dbf4bf7f25e954d4a..c11159f1d50b926eeb1c4ab96c343917726dfc80 100644 (file)
@@ -62,8 +62,8 @@ void set_default_settings()
        g_settings.setDefault("active_object_range", "2");
        g_settings.setDefault("max_simultaneous_block_sends_per_client", "1");
        g_settings.setDefault("max_simultaneous_block_sends_server_total", "4");
-       g_settings.setDefault("water_moves", "true");
-       g_settings.setDefault("disable_water_climb", "true");
+       //g_settings.setDefault("water_moves", "true");
+       //g_settings.setDefault("disable_water_climb", "true");
        //g_settings.setDefault("endless_water", "true");
        g_settings.setDefault("max_block_send_distance", "6");
        g_settings.setDefault("max_block_generate_distance", "6");
index 269948e86bcc2b77ed08e260253651a3963d421b..888b6da50108aa5131cea024c2cbe291da7f489e 100644 (file)
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define LIGHT_HEADER
 
 #include "common_irrlicht.h"
+#include "debug.h"
 
 /*
        Day/night cache:
@@ -78,7 +79,7 @@ inline u8 decode_light(u8 light)
                return light_decode_table[LIGHT_MAX];
        
        if(light > LIGHT_MAX)
-               throw;
+               light = LIGHT_MAX;
        
        return light_decode_table[light];
 }
index 61f791f8686de768eb0161b603a554acccf61168..3101583cf02c4154761da8035b52f50a4791cda3 100644 (file)
@@ -116,12 +116,16 @@ TODO: Startup and configuration menu
 \r
 Graphics:\r
 \r
+TODO: \r
+\r
 TODO: Optimize day/night mesh updating somehow\r
       - create copies of all textures for all lighting values and only\r
            change texture for material?\r
          - Umm... the collecting of the faces is the slow part\r
            -> what about just changing the color values of the existing\r
                   meshbuffers? It should go quite fast.\r
+                  - This is not easy; There'd need to be a buffer somewhere\r
+                    that would contain the night and day lighting values.\r
 \r
 TODO: Draw big amounts of torches better (that is, throw them in the\r
       same meshbuffer (can the meshcollector class be used?))\r
@@ -129,9 +133,13 @@ TODO: Draw big amounts of torches better (that is, throw them in the
 TODO: Combine MapBlock's face caches to so big pieces that VBO\r
       gets used\r
       - That is >500 vertices\r
+         - This is not easy; all the MapBlocks close to the player would\r
+           still need to be drawn separately and combining the blocks\r
+               would have to happen in a background thread\r
 \r
 TODO: Make fetching sector's blocks more efficient when rendering\r
       sectors that have very large amounts of blocks (on client)\r
+         - Is this necessary at all?\r
 \r
 Configuration:\r
 \r
@@ -210,6 +218,9 @@ TODO: Map generator version 2
        - There could be a certain height (to which mountains only reach)\r
          where some minerals are found\r
 \r
+FIXME: The new pre-sunlight-propagation code messes up with initial\r
+       water lighting\r
+\r
 Doing now:\r
 ======================================================================\r
 \r
index 170868f1073ff6bb3ef9aa948d730553b475406a..612649100f76f975fbd2808c4302363f0070237a 100644 (file)
@@ -926,6 +926,37 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
                MapBlock *block = i.getNode()->getValue();
                block->updateDayNightDiff();
        }
+
+       /*
+               Add neighboring liquid nodes and the node itself if it is
+               liquid (=water node was added) to transform queue.
+       */
+       v3s16 dirs[7] = {
+               v3s16(0,0,0), // self
+               v3s16(0,0,1), // back
+               v3s16(0,1,0), // top
+               v3s16(1,0,0), // right
+               v3s16(0,0,-1), // front
+               v3s16(0,-1,0), // bottom
+               v3s16(-1,0,0), // left
+       };
+       for(u16 i=0; i<7; i++)
+       {
+               try
+               {
+
+               v3s16 p2 = p + dirs[i];
+               
+               MapNode n2 = getNode(p2);
+               if(content_liquid(n2.d))
+               {
+                       m_transforming_liquid.push_back(p2);
+               }
+               
+               }catch(InvalidPositionException &e)
+               {
+               }
+       }
 }
 
 /*
@@ -1063,6 +1094,35 @@ void Map::removeNodeAndUpdate(v3s16 p,
                MapBlock *block = i.getNode()->getValue();
                block->updateDayNightDiff();
        }
+
+       /*
+               Add neighboring liquid nodes to transform queue.
+       */
+       v3s16 dirs[6] = {
+               v3s16(0,0,1), // back
+               v3s16(0,1,0), // top
+               v3s16(1,0,0), // right
+               v3s16(0,0,-1), // front
+               v3s16(0,-1,0), // bottom
+               v3s16(-1,0,0), // left
+       };
+       for(u16 i=0; i<6; i++)
+       {
+               try
+               {
+
+               v3s16 p2 = p + dirs[i];
+               
+               MapNode n2 = getNode(p2);
+               if(content_liquid(n2.d))
+               {
+                       m_transforming_liquid.push_back(p2);
+               }
+               
+               }catch(InvalidPositionException &e)
+               {
+               }
+       }
 }
 
 #ifndef SERVER
@@ -1303,6 +1363,276 @@ void Map::PrintInfo(std::ostream &out)
        out<<"Map: ";
 }
 
+#define WATER_DROP_BOOST 4
+
+void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
+{
+       DSTACK(__FUNCTION_NAME);
+       TimeTaker timer("transformLiquids()");
+
+       u32 loopcount = 0;
+       u32 initial_size = m_transforming_liquid.size();
+       while(m_transforming_liquid.size() != 0)
+       {
+               v3s16 p0 = m_transforming_liquid.pop_front();
+
+               MapNode n0 = getNode(p0);
+               
+               // Don't deal with non-liquids
+               if(content_liquid(n0.d) == false)
+                       continue;
+
+               bool is_source = !content_flowing_liquid(n0.d);
+               
+               u8 liquid_level = 8;
+               if(is_source == false)
+                       liquid_level = n0.param2 & 0x0f;
+               
+               // Turn possible source into non-source
+               u8 nonsource_c = make_liquid_flowing(n0.d);
+
+               /*
+                       If not source, check that some node flows into this one
+                       and what is the level of liquid in this one
+               */
+               if(is_source == false)
+               {
+                       s8 new_liquid_level_max = -1;
+
+                       v3s16 dirs_from[5] = {
+                               v3s16(0,1,0), // top
+                               v3s16(0,0,1), // back
+                               v3s16(1,0,0), // right
+                               v3s16(0,0,-1), // front
+                               v3s16(-1,0,0), // left
+                       };
+                       for(u16 i=0; i<5; i++)
+                       {
+                               try
+                               {
+
+                               bool from_top = (i==0);
+
+                               v3s16 p2 = p0 + dirs_from[i];
+                               MapNode n2 = getNode(p2);
+
+                               if(content_liquid(n2.d))
+                               {
+                                       u8 n2_nonsource_c = make_liquid_flowing(n2.d);
+                                       // Check that the liquids are the same type
+                                       if(n2_nonsource_c != nonsource_c)
+                                       {
+                                               dstream<<"WARNING: Not handling: different liquids"
+                                                               " collide"<<std::endl;
+                                               continue;
+                                       }
+                                       bool n2_is_source = !content_flowing_liquid(n2.d);
+                                       s8 n2_liquid_level = 8;
+                                       if(n2_is_source == false)
+                                               n2_liquid_level = n2.param2 & 0x07;
+                                       
+                                       s8 new_liquid_level = -1;
+                                       if(from_top)
+                                       {
+                                               //new_liquid_level = 7;
+                                               if(n2_liquid_level >= 7 - WATER_DROP_BOOST)
+                                                       new_liquid_level = 7;
+                                               else
+                                                       new_liquid_level = n2_liquid_level + WATER_DROP_BOOST;
+                                       }
+                                       else if(n2_liquid_level > 0)
+                                       {
+                                               new_liquid_level = n2_liquid_level - 1;
+                                       }
+
+                                       if(new_liquid_level > new_liquid_level_max)
+                                               new_liquid_level_max = new_liquid_level;
+                               }
+
+                               }catch(InvalidPositionException &e)
+                               {
+                               }
+                       } //for
+                       
+                       /*
+                               If liquid level should be something else, update it and
+                               add all the neighboring water nodes to the transform queue.
+                       */
+                       if(new_liquid_level_max != liquid_level)
+                       {
+                               if(new_liquid_level_max == -1)
+                               {
+                                       // Remove water alltoghether
+                                       n0.d = CONTENT_AIR;
+                                       n0.param2 = 0;
+                                       setNode(p0, n0);
+                               }
+                               else
+                               {
+                                       n0.param2 = new_liquid_level_max;
+                                       setNode(p0, n0);
+                               }
+                               
+                               // Block has been modified
+                               {
+                                       v3s16 blockpos = getNodeBlockPos(p0);
+                                       MapBlock *block = getBlockNoCreateNoEx(blockpos);
+                                       if(block != NULL)
+                                               modified_blocks.insert(blockpos, block);
+                               }
+                               
+                               /*
+                                       Add neighboring non-source liquid nodes to transform queue.
+                               */
+                               v3s16 dirs[6] = {
+                                       v3s16(0,0,1), // back
+                                       v3s16(0,1,0), // top
+                                       v3s16(1,0,0), // right
+                                       v3s16(0,0,-1), // front
+                                       v3s16(0,-1,0), // bottom
+                                       v3s16(-1,0,0), // left
+                               };
+                               for(u16 i=0; i<6; i++)
+                               {
+                                       try
+                                       {
+
+                                       v3s16 p2 = p0 + dirs[i];
+                                       
+                                       MapNode n2 = getNode(p2);
+                                       if(content_flowing_liquid(n2.d))
+                                       {
+                                               m_transforming_liquid.push_back(p2);
+                                       }
+                                       
+                                       }catch(InvalidPositionException &e)
+                                       {
+                                       }
+                               }
+                       }
+               }
+               
+               // Get a new one from queue if the node has turned into non-water
+               if(content_liquid(n0.d) == false)
+                       continue;
+
+               /*
+                       Flow water from this node
+               */
+               v3s16 dirs_to[5] = {
+                       v3s16(0,-1,0), // bottom
+                       v3s16(0,0,1), // back
+                       v3s16(1,0,0), // right
+                       v3s16(0,0,-1), // front
+                       v3s16(-1,0,0), // left
+               };
+               for(u16 i=0; i<5; i++)
+               {
+                       try
+                       {
+
+                       bool to_bottom = (i == 0);
+
+                       // If liquid is at lowest possible height, it's not going
+                       // anywhere except down
+                       if(liquid_level == 0 && to_bottom == false)
+                               continue;
+                       
+                       u8 liquid_next_level = 0;
+                       // If going to bottom
+                       if(to_bottom)
+                       {
+                               //liquid_next_level = 7;
+                               if(liquid_level >= 7 - WATER_DROP_BOOST)
+                                       liquid_next_level = 7;
+                               else
+                                       liquid_next_level = liquid_level + WATER_DROP_BOOST;
+                       }
+                       else
+                               liquid_next_level = liquid_level - 1;
+
+                       bool n2_changed = false;
+                       bool flowed = false;
+                       
+                       v3s16 p2 = p0 + dirs_to[i];
+
+                       MapNode n2 = getNode(p2);
+
+                       if(content_liquid(n2.d))
+                       {
+                               u8 n2_nonsource_c = make_liquid_flowing(n2.d);
+                               // Check that the liquids are the same type
+                               if(n2_nonsource_c != nonsource_c)
+                               {
+                                       dstream<<"WARNING: Not handling: different liquids"
+                                                       " collide"<<std::endl;
+                                       continue;
+                               }
+                               bool n2_is_source = !content_flowing_liquid(n2.d);
+                               u8 n2_liquid_level = 8;
+                               if(n2_is_source == false)
+                                       n2_liquid_level = n2.param2 & 0x07;
+                               
+                               if(to_bottom)
+                               {
+                                       flowed = true;
+                               }
+
+                               if(n2_is_source)
+                               {
+                                       // Just flow into the source, nothing changes.
+                                       // n2_changed is not set because destination didn't change
+                                       flowed = true;
+                               }
+                               else
+                               {
+                                       if(liquid_next_level > liquid_level)
+                                       {
+                                               n2.param2 = liquid_next_level;
+                                               setNode(p2, n2);
+
+                                               n2_changed = true;
+                                               flowed = true;
+                                       }
+                               }
+                       }
+                       else if(n2.d == CONTENT_AIR)
+                       {
+                               n2.d = nonsource_c;
+                               n2.param2 = liquid_next_level;
+                               setNode(p2, n2);
+                               
+                               n2_changed = true;
+                               flowed = true;
+                       }
+
+                       if(n2_changed)
+                       {
+                               m_transforming_liquid.push_back(p2);
+                               
+                               v3s16 blockpos = getNodeBlockPos(p2);
+                               MapBlock *block = getBlockNoCreateNoEx(blockpos);
+                               if(block != NULL)
+                                       modified_blocks.insert(blockpos, block);
+                       }
+                       
+                       // If n2_changed to bottom, don't flow anywhere else
+                       if(to_bottom && flowed)
+                               break;
+                               
+                       }catch(InvalidPositionException &e)
+                       {
+                       }
+               }
+
+               loopcount++;
+               //if(loopcount >= 100000)
+               if(loopcount >= initial_size * 1)
+                       break;
+       }
+       dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
+}
+
 /*
        ServerMap
 */
@@ -1327,15 +1657,20 @@ ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp):
                /*
                        NOTE: BEWARE: Too big amount of these will make map generation
                        slow. Especially those that are read by every block emerge.
+                       
+                       Fetch times:
+                       1000 points: 2-3ms
+                       5000 points: 15ms
+                       15000 points: 40ms
                */
                
-               for(u32 i=0; i<15000; i++)
+               for(u32 i=0; i<5000; i++)
                {
                        /*u32 lim = MAP_GENERATION_LIMIT;
                        if(i < 400)
                                lim = 2000;*/
 
-                       u32 lim = 1000 + MAP_GENERATION_LIMIT * i / 15000;
+                       u32 lim = 1000 + MAP_GENERATION_LIMIT * i / 5000;
 
                        v3s16 p(
                                -lim + myrand()%(lim*2),
@@ -1679,17 +2014,19 @@ MapSector * ServerMap::emergeSector(v2s16 p2d)
                Get local attributes
        */
        
-       //dstream<<"emergeSector(): Reading point attribute lists"<<std::endl;
-       
-       // Get plant amount from attributes
-       PointAttributeList *palist = m_padb.getList("plants_amount");
-       assert(palist);
-       /*float local_plants_amount =
-                       palist->getNearAttr(nodepos2d).getFloat();*/
-       float local_plants_amount =
-                       palist->getInterpolatedFloat(nodepos2d);
-
-       //dstream<<"emergeSector(): done."<<std::endl;
+       float local_plants_amount = 0.0;
+       {
+               //dstream<<"emergeSector(): Reading point attribute lists"<<std::endl;
+               //TimeTaker attrtimer("emergeSector() attribute fetch");
+               
+               // Get plant amount from attributes
+               PointAttributeList *palist = m_padb.getList("plants_amount");
+               assert(palist);
+               /*local_plants_amount =
+                               palist->getNearAttr(nodepos2d).getFloat();*/
+               local_plants_amount =
+                               palist->getInterpolatedFloat(nodepos2d);
+       }
 
        /*
                Generate sector heightmap
@@ -1988,6 +2325,12 @@ MapBlock * ServerMap::emergeBlock(
                                        n.d = water_material;
                                        n.setLight(LIGHTBANK_DAY,
                                                        diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
+                                       /*
+                                               Add to transforming liquid queue (in case it'd
+                                               start flowing)
+                                       */
+                                       v3s16 real_pos = v3s16(x0,y0,z0) + p*MAP_BLOCKSIZE;
+                                       m_transforming_liquid.push_back(real_pos);
                                }
                                // else air
                                else
@@ -2692,7 +3035,8 @@ continue_generating:
                core::map<v3s16, bool> light_sources;
                bool black_air_left = false;
                bool bottom_invalid =
-                               block->propagateSunlight(light_sources, true, &black_air_left);
+                               block->propagateSunlight(light_sources, true,
+                               &black_air_left, true);
 
                // If sunlight didn't reach everywhere and part of block is
                // above ground, lighting has to be properly updated
@@ -2700,6 +3044,11 @@ continue_generating:
                {
                        lighting_invalidated_blocks[block->getPos()] = block;
                }
+
+               if(bottom_invalid)
+               {
+                       lighting_invalidated_blocks[block->getPos()] = block;
+               }
        }
 
        /*
@@ -2739,7 +3088,7 @@ continue_generating:
        if(haxmode)
        {
                // Don't calculate lighting at all
-               lighting_invalidated_blocks.clear();
+               //lighting_invalidated_blocks.clear();
        }
 
        return block;
@@ -3523,11 +3872,12 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
 
                        // Total distance
                        f32 d = blockpos_relative.getLength();
-
+                       
+#if 1
                        /*
-                               Draw the faces of the block
+                               Update expired mesh
                        */
-#if 1
+
                        bool mesh_expired = false;
                        
                        {
@@ -3585,6 +3935,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
                                continue;
                        }*/
 #endif
+                       /*
+                               Draw the faces of the block
+                       */
                        {
                                JMutexAutoLock lock(block->mesh_mutex);
 
index 5cee3b7c09c058d1bd2d18be315570e35b947542..3b6b169e5d2b56cdc16a6b4def42ced5565522c9 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -236,6 +236,8 @@ public:
 
        // For debug printing
        virtual void PrintInfo(std::ostream &out);
+       
+       void transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks);
 
        /*
                Variables
index cf9114b20210f2879da2b7258a13b91b708c659e..8de81b7741c418cf4b761de8ae13e3b4a717d061 100644 (file)
@@ -146,6 +146,25 @@ u8 MapBlock::getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
                v3s16 face_dir)
 {
        try{
+               // DEBUG
+               /*{
+                       if(n.d == CONTENT_WATER)
+                       {
+                               u8 l = n.param2*2;
+                               if(l > LIGHT_MAX)
+                                       l = LIGHT_MAX;
+                               return l;
+                       }
+                       if(n2.d == CONTENT_WATER)
+                       {
+                               u8 l = n2.param2*2;
+                               if(l > LIGHT_MAX)
+                                       l = LIGHT_MAX;
+                               return l;
+                       }
+               }*/
+
+
                u8 light;
                u8 l1 = n.getLightBlend(daynight_ratio);
                u8 l2 = n2.getLightBlend(daynight_ratio);
@@ -645,10 +664,10 @@ void MapBlock::updateMesh(u32 daynight_ratio)
        
        mesh_new = new scene::SMesh();
        
+       MeshCollector collector;
+
        if(fastfaces_new.size() > 0)
        {
-               MeshCollector collector;
-
                for(u32 i=0; i<fastfaces_new.size(); i++)
                {
                        FastFace &f = fastfaces_new[i];
@@ -685,16 +704,6 @@ void MapBlock::updateMesh(u32 daynight_ratio)
                                assert(0);
                        }
                }
-
-               collector.fillMesh(mesh_new);
-
-               // Use VBO for mesh (this just would set this for ever buffer)
-               // This will lead to infinite memory usage because or irrlicht.
-               //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
-               
-               /*std::cout<<"MapBlock has "<<fastfaces_new.size()<<" faces "
-                               <<"and uses "<<mesh_new->getMeshBufferCount()
-                               <<" materials (meshbuffers)"<<std::endl;*/
        }
 
        /*
@@ -714,8 +723,6 @@ void MapBlock::updateMesh(u32 daynight_ratio)
                
                if(n.d == CONTENT_TORCH)
                {
-                       //scene::IMeshBuffer *buf = new scene::SMeshBuffer();
-                       scene::SMeshBuffer *buf = new scene::SMeshBuffer();
                        video::SColor c(255,255,255,255);
 
                        video::S3DVertex vertices[4] =
@@ -746,36 +753,266 @@ void MapBlock::updateMesh(u32 daynight_ratio)
                                vertices[i].Pos += intToFloat(p + getPosRelative());
                        }
 
-                       u16 indices[] = {0,1,2,2,3,0};
-                       buf->append(vertices, 4, indices, 6);
-
                        // Set material
-                       buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
-                       buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
-                       buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
-                       //buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
-                       buf->getMaterial().MaterialType
+                       video::SMaterial material;
+                       material.setFlag(video::EMF_LIGHTING, false);
+                       material.setFlag(video::EMF_BACK_FACE_CULLING, false);
+                       material.setFlag(video::EMF_BILINEAR_FILTER, false);
+                       //material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+                       material.MaterialType
                                        = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
                        if(dir == v3s16(0,-1,0))
-                               buf->getMaterial().setTexture(0,
+                               material.setTexture(0,
                                                g_irrlicht->getTexture(porting::getDataPath("torch_on_floor.png").c_str()));
                        else if(dir == v3s16(0,1,0))
-                               buf->getMaterial().setTexture(0,
+                               material.setTexture(0,
                                                g_irrlicht->getTexture(porting::getDataPath("torch_on_ceiling.png").c_str()));
                        // For backwards compatibility
                        else if(dir == v3s16(0,0,0))
-                               buf->getMaterial().setTexture(0,
+                               material.setTexture(0,
                                                g_irrlicht->getTexture(porting::getDataPath("torch_on_floor.png").c_str()));
                        else
-                               buf->getMaterial().setTexture(0, 
+                               material.setTexture(0, 
                                                g_irrlicht->getTexture(porting::getDataPath("torch.png").c_str()));
 
-                       // Add to mesh
-                       mesh_new->addMeshBuffer(buf);
-                       buf->drop();
+                       u16 indices[] = {0,1,2,2,3,0};
+                       // Add to mesh collector
+                       collector.append(material, vertices, 4, indices, 6);
+               }
+               else if(n.d == CONTENT_WATER)
+               {
+                       bool top_is_water = false;
+                       try{
+                               MapNode n = getNodeParent(v3s16(x,y+1,z));
+                               if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
+                                       top_is_water = true;
+                       }catch(InvalidPositionException &e){}
+
+                       video::SColor c(128,255,255,255);
+                       
+                       // Neighbor water levels (key = relative position)
+                       // Includes current node
+                       core::map<v3s16, f32> neighbor_levels;
+                       core::map<v3s16, u8> neighbor_contents;
+                       v3s16 neighbor_dirs[9] = {
+                               v3s16(0,0,0),
+                               v3s16(0,0,1),
+                               v3s16(0,0,-1),
+                               v3s16(1,0,0),
+                               v3s16(-1,0,0),
+                               v3s16(1,0,1),
+                               v3s16(-1,0,-1),
+                               v3s16(1,0,-1),
+                               v3s16(-1,0,1),
+                       };
+                       for(u32 i=0; i<9; i++)
+                       {
+                               u8 content = CONTENT_AIR;
+                               float level = -0.5 * BS;
+                               try{
+                                       v3s16 p2 = p + neighbor_dirs[i];
+                                       MapNode n2 = getNodeParent(p2);
+
+                                       content = n2.d;
+
+                                       if(n2.d == CONTENT_WATERSOURCE)
+                                               level = 0.5 * BS;
+                                       else if(n2.d == CONTENT_WATER)
+                                               level = (-0.5 + ((float)n2.param2 + 0.5) / 8.0) * BS;
+                               }
+                               catch(InvalidPositionException &e){}
+                               
+                               neighbor_levels.insert(neighbor_dirs[i], level);
+                               neighbor_contents.insert(neighbor_dirs[i], content);
+                       }
+
+                       //float water_level = (-0.5 + ((float)n.param2 + 0.5) / 8.0) * BS;
+                       //float water_level = neighbor_levels[v3s16(0,0,0)];
+
+                       // Corner heights (average between four waters)
+                       f32 corner_levels[4];
+                       
+                       v3s16 halfdirs[4] = {
+                               v3s16(0,0,0),
+                               v3s16(1,0,0),
+                               v3s16(1,0,1),
+                               v3s16(0,0,1),
+                       };
+                       for(u32 i=0; i<4; i++)
+                       {
+                               v3s16 cornerdir = halfdirs[i];
+                               float cornerlevel = 0;
+                               u32 valid_count = 0;
+                               for(u32 j=0; j<4; j++)
+                               {
+                                       v3s16 neighbordir = cornerdir - halfdirs[j];
+                                       u8 content = neighbor_contents[neighbordir];
+                                       // Special case for source nodes
+                                       if(content == CONTENT_WATERSOURCE)
+                                       {
+                                               cornerlevel = 0.5*BS;
+                                               valid_count = 1;
+                                               break;
+                                       }
+                                       else if(content == CONTENT_WATER)
+                                       {
+                                               cornerlevel += neighbor_levels[neighbordir];
+                                               valid_count++;
+                                       }
+                                       else if(content == CONTENT_AIR)
+                                       {
+                                               cornerlevel += -0.5*BS;
+                                               valid_count++;
+                                       }
+                               }
+                               if(valid_count > 0)
+                                       cornerlevel /= valid_count;
+                               corner_levels[i] = cornerlevel;
+                       }
+
+                       /*
+                               Generate sides
+                       */
+
+                       v3s16 side_dirs[4] = {
+                               v3s16(1,0,0),
+                               v3s16(-1,0,0),
+                               v3s16(0,0,1),
+                               v3s16(0,0,-1),
+                       };
+                       s16 side_corners[4][2] = {
+                               {1, 2},
+                               {3, 0},
+                               {2, 3},
+                               {0, 1},
+                       };
+                       for(u32 i=0; i<4; i++)
+                       {
+                               v3s16 dir = side_dirs[i];
+
+                               //float neighbor_level = neighbor_levels[dir];
+                               /*if(neighbor_level > -0.5*BS + 0.001)
+                                       continue;*/
+                               /*if(neighbor_level > water_level - 0.1*BS)
+                                       continue;*/
+
+                               u8 neighbor_content = neighbor_contents[dir];
+
+                               if(neighbor_content != CONTENT_AIR
+                                               && neighbor_content != CONTENT_WATER)
+                                       continue;
+                               
+                               bool neighbor_is_water = (neighbor_content == CONTENT_WATER);
+
+                               if(neighbor_is_water == true && top_is_water == false)
+                                       continue;
+                               
+                               video::S3DVertex vertices[4] =
+                               {
+                                       /*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
+                                       video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
+                                       video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
+                                       video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/
+                                       video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
+                                       video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
+                                       video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
+                                       video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),
+                               };
+                               
+                               if(top_is_water)
+                               {
+                                       vertices[2].Pos.Y = 0.5*BS;
+                                       vertices[3].Pos.Y = 0.5*BS;
+                               }
+                               else
+                               {
+                                       vertices[2].Pos.Y = corner_levels[side_corners[i][0]];
+                                       vertices[3].Pos.Y = corner_levels[side_corners[i][1]];
+                               }
+
+                               if(neighbor_is_water)
+                               {
+                                       vertices[0].Pos.Y = corner_levels[side_corners[i][1]];
+                                       vertices[1].Pos.Y = corner_levels[side_corners[i][0]];
+                               }
+                               else
+                               {
+                                       vertices[0].Pos.Y = -0.5*BS;
+                                       vertices[1].Pos.Y = -0.5*BS;
+                               }
+                               
+                               for(s32 j=0; j<4; j++)
+                               {
+                                       if(dir == v3s16(0,0,1))
+                                               vertices[j].Pos.rotateXZBy(0);
+                                       if(dir == v3s16(0,0,-1))
+                                               vertices[j].Pos.rotateXZBy(180);
+                                       if(dir == v3s16(-1,0,0))
+                                               vertices[j].Pos.rotateXZBy(90);
+                                       if(dir == v3s16(1,0,-0))
+                                               vertices[j].Pos.rotateXZBy(-90);
+
+                                       vertices[j].Pos += intToFloat(p + getPosRelative());
+                               }
+
+                               // Set material
+                               video::SMaterial material;
+                               material.setFlag(video::EMF_LIGHTING, false);
+                               material.setFlag(video::EMF_BACK_FACE_CULLING, false);
+                               material.setFlag(video::EMF_BILINEAR_FILTER, false);
+                               material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
+                               material.setTexture(0,
+                                               g_irrlicht->getTexture(porting::getDataPath("water.png").c_str()));
+
+                               u16 indices[] = {0,1,2,2,3,0};
+                               // Add to mesh collector
+                               collector.append(material, vertices, 4, indices, 6);
+                       }
+                       
+                       /*
+                               Generate top side, if appropriate
+                       */
+                       
+                       if(top_is_water == false)
+                       {
+                               video::S3DVertex vertices[4] =
+                               {
+                                       video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1),
+                                       video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1),
+                                       video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
+                                       video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),
+                               };
+
+                               for(s32 i=0; i<4; i++)
+                               {
+                                       //vertices[i].Pos.Y += water_level;
+                                       //vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
+                                       vertices[i].Pos.Y += corner_levels[i];
+                                       vertices[i].Pos += intToFloat(p + getPosRelative());
+                               }
+
+                               // Set material
+                               video::SMaterial material;
+                               material.setFlag(video::EMF_LIGHTING, false);
+                               material.setFlag(video::EMF_BACK_FACE_CULLING, false);
+                               material.setFlag(video::EMF_BILINEAR_FILTER, false);
+                               material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
+                               material.setTexture(0,
+                                               g_irrlicht->getTexture(porting::getDataPath("water.png").c_str()));
+
+                               u16 indices[] = {0,1,2,2,3,0};
+                               // Add to mesh collector
+                               collector.append(material, vertices, 4, indices, 6);
+                       }
                }
        }
+
+       /*
+               Add stuff from collector to mesh
+       */
        
+       collector.fillMesh(mesh_new);
+
        /*
                Do some stuff to the mesh
        */
@@ -792,6 +1029,14 @@ void MapBlock::updateMesh(u32 daynight_ratio)
                mesh_new = NULL;
        }
 
+       // Use VBO for mesh (this just would set this for ever buffer)
+       // This will lead to infinite memory usage because or irrlicht.
+       //mesh_new->setHardwareMappingHint(scene::EHM_STATIC);
+       
+       /*std::cout<<"MapBlock has "<<fastfaces_new.size()<<" faces "
+                       <<"and uses "<<mesh_new->getMeshBufferCount()
+                       <<" materials (meshbuffers)"<<std::endl;*/
+       
        /*
                Replace the mesh
        */
@@ -872,7 +1117,8 @@ void MapBlock::updateMesh(u32 daynight_ratio)
        air is left in block.
 */
 bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
-               bool remove_light, bool *black_air_left)
+               bool remove_light, bool *black_air_left,
+               bool grow_grass)
 {
        // Whether the sunlight at the top of the bottom block is valid
        bool block_below_is_valid = true;
@@ -962,10 +1208,23 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
                                }
                                else if(n.light_propagates() == false)
                                {
-                                       // Turn mud into grass
-                                       if(n.d == CONTENT_MUD && current_light == LIGHT_SUN)
+                                       if(grow_grass)
                                        {
-                                               n.d = CONTENT_GRASS;
+                                               bool upper_is_air = false;
+                                               try
+                                               {
+                                                       if(getNodeParent(pos+v3s16(0,1,0)).d == CONTENT_AIR)
+                                                               upper_is_air = true;
+                                               }
+                                               catch(InvalidPositionException &e)
+                                               {
+                                               }
+                                               // Turn mud into grass
+                                               if(upper_is_air && n.d == CONTENT_MUD
+                                                               && current_light == LIGHT_SUN)
+                                               {
+                                                       n.d = CONTENT_GRASS;
+                                               }
                                        }
 
                                        // A solid object is on the way.
index e4f93a031c4d61c72b80252f59394a30b38a95d8..dd527766861c6ae7e128e847c366bca5b10054cd 100644 (file)
@@ -315,7 +315,8 @@ public:
        
        // See comments in mapblock.cpp
        bool propagateSunlight(core::map<v3s16, bool> & light_sources,
-                       bool remove_light=false, bool *black_air_left=NULL);
+                       bool remove_light=false, bool *black_air_left=NULL,
+                       bool grow_grass=false);
        
        // Copies data to VoxelManipulator to getPosRelative()
        void copyTo(VoxelManipulator &dst);
index de6953b785382173d33e63e3be9aee267cf73bd0..59e40935c0e85eda949978170b5cc8a3c900224d 100644 (file)
@@ -35,7 +35,8 @@ u16 g_content_tiles[USEFUL_CONTENT_COUNT][6] =
 {
        {TILE_STONE,TILE_STONE,TILE_STONE,TILE_STONE,TILE_STONE,TILE_STONE},
        {TILE_GRASS,TILE_MUD,TILE_MUD_WITH_GRASS,TILE_MUD_WITH_GRASS,TILE_MUD_WITH_GRASS,TILE_MUD_WITH_GRASS},
-       {TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER},
+       //{TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER,TILE_WATER},
+       {TILE_NONE,TILE_NONE,TILE_NONE,TILE_NONE,TILE_NONE,TILE_NONE},
        {TILE_NONE,TILE_NONE,TILE_NONE,TILE_NONE,TILE_NONE,TILE_NONE},
        {TILE_TREE_TOP,TILE_TREE_TOP,TILE_TREE,TILE_TREE,TILE_TREE,TILE_TREE},
        {TILE_LEAVES,TILE_LEAVES,TILE_LEAVES,TILE_LEAVES,TILE_LEAVES,TILE_LEAVES},
index a759f807ed4848ccb6a8c1c6b1f73b36e9b79ac7..e3b921a66604405c5bc44f4f6a89330f7774bdcc 100644 (file)
@@ -108,7 +108,7 @@ inline bool sunlight_propagates_content(u8 m)
 inline u8 content_solidness(u8 m)
 {
        // As of now, every pseudo node like torches are added to this
-       if(m == CONTENT_AIR || m == CONTENT_TORCH)
+       if(m == CONTENT_AIR || m == CONTENT_TORCH || m == CONTENT_WATER)
                return 0;
        if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
                return 1;
@@ -121,12 +121,30 @@ inline bool content_walkable(u8 m)
        return (m != CONTENT_AIR && m != CONTENT_WATER && m != CONTENT_WATERSOURCE && m != CONTENT_TORCH);
 }
 
-// A liquid resists fast movement
 inline bool content_liquid(u8 m)
 {
        return (m == CONTENT_WATER || m == CONTENT_WATERSOURCE);
 }
 
+inline bool content_flowing_liquid(u8 m)
+{
+       return (m == CONTENT_WATER);
+}
+
+inline bool content_liquid_source(u8 m)
+{
+       return (m == CONTENT_WATERSOURCE);
+}
+
+// CONTENT_WATER || CONTENT_WATERSOURCE -> CONTENT_WATER
+// CONTENT_LAVA || CONTENT_LAVASOURCE -> CONTENT_LAVA
+inline u8 make_liquid_flowing(u8 m)
+{
+       if(m == CONTENT_WATER || m == CONTENT_WATERSOURCE)
+               return CONTENT_WATER;
+       assert(0);
+}
+
 // Pointable contents can be pointed to in the map
 inline bool content_pointable(u8 m)
 {
@@ -349,6 +367,8 @@ struct MapNode
        
        union
        {
+               u8 param2;
+               
                /*
                        Pressure for liquids
                */
index 312e2b6d9b3146ca290041846e191dc44d8705c3..17004a803480cc853a96aaceeac46da1139d4803 100644 (file)
@@ -971,7 +971,8 @@ Server::Server(
        m_time_of_day_send_timer(0),
        m_uptime(0)
 {
-       m_flowwater_timer = 0.0;
+       //m_flowwater_timer = 0.0;
+       m_liquid_transform_timer = 0.0;
        m_print_info_timer = 0.0;
        m_objectdata_timer = 0.0;
        m_emergethread_trigger_timer = 0.0;
@@ -1140,9 +1141,54 @@ void Server::AsyncRunStep()
        /*
                Do background stuff
        */
-
+       
+       /*
+               Transform liquids
+       */
+       m_liquid_transform_timer += dtime;
+       if(m_liquid_transform_timer >= 1.00)
        {
-               //m_env.getMap().
+               m_liquid_transform_timer -= 1.00;
+               
+               JMutexAutoLock lock(m_env_mutex);
+               
+               core::map<v3s16, MapBlock*> modified_blocks;
+               m_env.getMap().transformLiquids(modified_blocks);
+#if 0          
+               /*
+                       Update lighting
+               */
+               core::map<v3s16, MapBlock*> lighting_modified_blocks;
+               ServerMap &map = ((ServerMap&)m_env.getMap());
+               map.updateLighting(modified_blocks, lighting_modified_blocks);
+               
+               // Add blocks modified by lighting to modified_blocks
+               for(core::map<v3s16, MapBlock*>::Iterator
+                               i = lighting_modified_blocks.getIterator();
+                               i.atEnd() == false; i++)
+               {
+                       MapBlock *block = i.getNode()->getValue();
+                       modified_blocks.insert(block->getPos(), block);
+               }
+#endif
+               /*
+                       Set the modified blocks unsent for all the clients
+               */
+               
+               JMutexAutoLock lock2(m_con_mutex);
+
+               for(core::map<u16, RemoteClient*>::Iterator
+                               i = m_clients.getIterator();
+                               i.atEnd() == false; i++)
+               {
+                       RemoteClient *client = i.getNode()->getValue();
+                       
+                       if(modified_blocks.size() > 0)
+                       {
+                               // Remove block from sent history
+                               client->SetBlocksNotSent(modified_blocks);
+                       }
+               }
        }
 
 #if 0
index a1c4a1cd72b79b0bc3d343be5751e60ca62bf89d..4bdaa84550a7e7261e0a8d4db8d3d7ed9f0d6717 100644 (file)
@@ -457,7 +457,8 @@ private:
        void handlePeerChange(PeerChange &c);
        void handlePeerChanges();
        
-       float m_flowwater_timer;
+       //float m_flowwater_timer;
+       float m_liquid_transform_timer;
        float m_print_info_timer;
        float m_objectdata_timer;
        float m_emergethread_trigger_timer;
index a38d15f307a3d34df52b89073689e13aa8fa8a59..897390dba8d7f2ff7736ee09c2beff803d6e7f47 100644 (file)
@@ -1608,7 +1608,7 @@ public:
                return true;
        }
 
-       void pop_front()
+       Value pop_front()
        {
                typename core::list<Value>::Iterator i = m_list.begin();
                Value value = *i;
@@ -1617,6 +1617,12 @@ public:
                return value;
        }
 
+       u32 size()
+       {
+               assert(m_list.size() == m_map.size());
+               return m_list.size();
+       }
+
 private:
        core::map<Value, u8> m_map;
        core::list<Value> m_list;