]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/voxel.cpp
.
[dragonfireclient.git] / src / voxel.cpp
index b85ba866642e5dd6747b771c621ed2e9460fcf4b..7ba4e21c6ef0d2dd8fdc78978c70e0d8245a56b8 100644 (file)
@@ -21,8 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "map.h"
 
 // For TimeTaker
-#include "main.h"
 #include "utility.h"
+#include "gettime.h"
 
 /*
        Debug stuff
@@ -41,6 +41,7 @@ VoxelManipulator::VoxelManipulator():
        m_data(NULL),
        m_flags(NULL)
 {
+       m_disable_water_climb = false;
 }
 
 VoxelManipulator::~VoxelManipulator()
@@ -103,13 +104,13 @@ void VoxelManipulator::print(std::ostream &o, VoxelPrintMode mode)
                                        }
                                        else if(mode == VOXELPRINT_WATERPRESSURE)
                                        {
-                                               if(m == MATERIAL_WATER)
+                                               if(m == CONTENT_WATER)
                                                {
                                                        c = 'w';
                                                        if(pr <= 9)
                                                                c = pr + '0';
                                                }
-                                               else if(m == MATERIAL_AIR)
+                                               else if(liquid_replaces_content(m))
                                                {
                                                        c = ' ';
                                                }
@@ -137,7 +138,7 @@ void VoxelManipulator::addArea(VoxelArea area)
        if(m_area.contains(area))
                return;
        
-       TimeTaker timer("addArea", g_device, &addarea_time);
+       TimeTaker timer("addArea", &addarea_time);
 
        // Calculate new area
        VoxelArea new_area;
@@ -220,76 +221,11 @@ void VoxelManipulator::copyFrom(MapNode *src, VoxelArea src_area,
        }
 }
 
-void VoxelManipulator::interpolate(VoxelArea area)
-{
-       VoxelArea emerge_area = area;
-       emerge_area.MinEdge -= v3s16(1,1,1);
-       emerge_area.MaxEdge += v3s16(1,1,1);
-       emerge(emerge_area);
-
-       SharedBuffer<u8> buf(area.getVolume());
-
-       for(s32 z=area.MinEdge.Z; z<=area.MaxEdge.Z; z++)
-       for(s32 y=area.MinEdge.Y; y<=area.MaxEdge.Y; y++)
-       for(s32 x=area.MinEdge.X; x<=area.MaxEdge.X; x++)
-       {
-               v3s16 p(x,y,z);
-
-               v3s16 dirs[] = {
-                       v3s16(1,1,0),
-                       v3s16(1,0,1),
-                       v3s16(1,-1,0),
-                       v3s16(1,0,-1),
-                       v3s16(-1,1,0),
-                       v3s16(-1,0,1),
-                       v3s16(-1,-1,0),
-                       v3s16(-1,0,-1),
-               };
-               //const v3s16 *dirs = g_26dirs;
-               
-               s16 total = 0;
-               s16 airness = 0;
-               u8 m = MATERIAL_IGNORE;
-
-               for(s16 i=0; i<8; i++)
-               //for(s16 i=0; i<26; i++)
-               {
-                       v3s16 p2 = p + dirs[i];
-
-                       u8 f = m_flags[m_area.index(p2)];
-                       assert(!(f & VOXELFLAG_NOT_LOADED));
-                       if(f & VOXELFLAG_INEXISTENT)
-                               continue;
-
-                       MapNode &n = m_data[m_area.index(p2)];
-
-                       airness += (n.d == MATERIAL_AIR) ? 1 : -1;
-                       total++;
-
-                       if(m == MATERIAL_IGNORE && n.d != MATERIAL_AIR)
-                               m = n.d;
-               }
-
-               // 1 if air, 0 if not
-               buf[area.index(p)] = airness > -total/2 ? MATERIAL_AIR : m;
-               //buf[area.index(p)] = airness > -total ? MATERIAL_AIR : m;
-               //buf[area.index(p)] = airness >= -7 ? MATERIAL_AIR : m;
-       }
-
-       for(s32 z=area.MinEdge.Z; z<=area.MaxEdge.Z; z++)
-       for(s32 y=area.MinEdge.Y; y<=area.MaxEdge.Y; y++)
-       for(s32 x=area.MinEdge.X; x<=area.MaxEdge.X; x++)
-       {
-               v3s16 p(x,y,z);
-               m_data[m_area.index(p)].d = buf[area.index(p)];
-       }
-}
-
 
 void VoxelManipulator::clearFlag(u8 flags)
 {
        // 0-1ms on moderate area
-       TimeTaker timer("clearFlag", g_device, &clearflag_time);
+       TimeTaker timer("clearFlag", &clearflag_time);
 
        v3s16 s = m_area.getExtent();
 
@@ -335,23 +271,26 @@ int VoxelManipulator::getWaterPressure(v3s16 p, s16 &highest_y, int recur_count)
        if(p.Y > highest_y)
                highest_y = p.Y;
        
-       recur_count++;
-       if(recur_count > 30)
+       /*if(recur_count > 1000)
                throw ProcessingLimitException
-                               ("getWaterPressure recur_count limit reached");
+                               ("getWaterPressure recur_count limit reached");*/
+       
+       if(recur_count > 10000)
+               return -1;
+       
+       recur_count++;
 
        v3s16 dirs[6] = {
                v3s16(0,1,0), // top
-               v3s16(-1,0,0), // left
-               v3s16(1,0,0), // right
-               v3s16(0,0,-1), // front
                v3s16(0,0,1), // back
+               v3s16(0,0,-1), // front
+               v3s16(1,0,0), // right
+               v3s16(-1,0,0), // left
                v3s16(0,-1,0), // bottom
        };
 
        // Load neighboring nodes
-       // TODO: A bigger area would be better
-       emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)));
+       emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)), 1);
 
        s32 i;
        for(i=0; i<6; i++)
@@ -363,18 +302,19 @@ int VoxelManipulator::getWaterPressure(v3s16 p, s16 &highest_y, int recur_count)
                        continue;
                MapNode &n = m_data[m_area.index(p2)];
                // Ignore non-liquid nodes
-               if(material_liquid(n.d) == false)
+               if(content_liquid(n.d) == false)
                        continue;
 
                int pr;
-               
-               // If at surface
-               /*if(n.pressure == 1)
+
+               // If at ocean surface
+               if(n.pressure == 1 && n.d == CONTENT_WATERSOURCE)
+               //if(n.pressure == 1) // Causes glitches but is fast
                {
                        pr = 1;
                }
                // Otherwise recurse more
-               else*/
+               else
                {
                        pr = getWaterPressure(p2, highest_y, recur_count);
                        if(pr == -1)
@@ -410,10 +350,21 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
                core::map<v3s16, u8> &active_nodes,
                int recur_count)
 {
+       //if(recur_count > 10000)
+               /*throw ProcessingLimitException
+                               ("spreadWaterPressure recur_count limit reached");*/
+       if(recur_count > 10)
+               return;
        recur_count++;
-       if(recur_count > 10000)
-               throw ProcessingLimitException
-                               ("spreadWaterPressure recur_count limit reached");
+       
+       /*dstream<<"spreadWaterPressure: p=("
+                       <<p.X<<","<<p.Y<<","<<p.Z<<")"
+                       <<", oldpr="<<(int)m_data[m_area.index(p)].pressure
+                       <<", pr="<<pr
+                       <<", recur_count="<<recur_count
+                       <<", request_area=";
+       request_area.print(dstream);
+       dstream<<std::endl;*/
 
        m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED3;
        m_data[m_area.index(p)].pressure = pr;
@@ -428,7 +379,7 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
        };
 
        // Load neighboring nodes
-       emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)));
+       emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)), 2);
 
        s32 i;
        for(i=0; i<6; i++)
@@ -449,12 +400,16 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
                        NOTE: Do not remove anything from there. We cannot know
                              here if some other neighbor of it causes flow.
                */
-               if(n.d == MATERIAL_AIR)
+               if(liquid_replaces_content(n.d))
                {
                        bool pressure_causes_flow = false;
-                       // If block is at top
+                       // If empty block is at top
                        if(i == 0)
                        {
+                               if(m_disable_water_climb)
+                                       continue;
+                               
+                               //if(pr >= PRESERVE_WATER_VOLUME ? 3 : 2)
                                if(pr >= 3)
                                        pressure_causes_flow = true;
                        }
@@ -466,6 +421,7 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
                        // If block is at side
                        else
                        {
+                               //if(pr >= PRESERVE_WATER_VOLUME ? 2 : 1)
                                if(pr >= 2)
                                        pressure_causes_flow = true;
                        }
@@ -479,7 +435,7 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
                }
 
                // Ignore non-liquid nodes
-               if(material_liquid(n.d) == false)
+               if(content_liquid(n.d) == false)
                        continue;
 
                int pr2 = pr;
@@ -495,9 +451,18 @@ void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
                        if(pr2 < 255)
                                pr2++;
                }
+
+               /*if(m_disable_water_climb)
+               {
+                       if(pr2 > 3)
+                               pr2 = 3;
+               }*/
                
                // Ignore if correct pressure is already set and is not on
-               // request_area
+               // request_area.
+               // Thus, request_area can be used for updating as much
+               // pressure info in some area as possible to possibly
+               // make some calls to getWaterPressure unnecessary.
                if(n.pressure == pr2 && request_area.contains(p2) == false)
                        continue;
 
@@ -509,10 +474,9 @@ void VoxelManipulator::updateAreaWaterPressure(VoxelArea a,
                core::map<v3s16, u8> &active_nodes,
                bool checked3_is_clear)
 {
-       TimeTaker timer("updateAreaWaterPressure", g_device,
-                       &updateareawaterpressure_time);
+       TimeTaker timer("updateAreaWaterPressure", &updateareawaterpressure_time);
 
-       emerge(a);
+       emerge(a, 3);
        
        bool checked2_clear = false;
        
@@ -537,7 +501,7 @@ void VoxelManipulator::updateAreaWaterPressure(VoxelArea a,
                        continue;
                MapNode &n = m_data[m_area.index(p)];
                // Ignore non-liquid nodes
-               if(material_liquid(n.d) == false)
+               if(content_liquid(n.d) == false)
                        continue;
                
                if(checked2_clear == false)
@@ -555,7 +519,7 @@ void VoxelManipulator::updateAreaWaterPressure(VoxelArea a,
                try
                {
                        // 0-1ms @ recur_count <= 100
-                       //TimeTaker timer("getWaterPressure", g_device);
+                       //TimeTaker timer("getWaterPressure", g_irrlicht);
                        pr = getWaterPressure(p, highest_y, recur_count);
                }
                catch(ProcessingLimitException &e)
@@ -583,7 +547,7 @@ void VoxelManipulator::updateAreaWaterPressure(VoxelArea a,
                try
                {
                        // 0ms
-                       //TimeTaker timer("spreadWaterPressure", g_device);
+                       //TimeTaker timer("spreadWaterPressure", g_irrlicht);
                        spreadWaterPressure(p, pr, a, active_nodes, 0);
                }
                catch(ProcessingLimitException &e)
@@ -596,20 +560,21 @@ void VoxelManipulator::updateAreaWaterPressure(VoxelArea a,
 bool VoxelManipulator::flowWater(v3s16 removed_pos,
                core::map<v3s16, u8> &active_nodes,
                int recursion_depth, bool debugprint,
-               int *counter, int counterlimit)
+               u32 stoptime)
 {
        v3s16 dirs[6] = {
                v3s16(0,1,0), // top
-               v3s16(-1,0,0), // left
-               v3s16(1,0,0), // right
                v3s16(0,0,-1), // front
                v3s16(0,0,1), // back
+               v3s16(-1,0,0), // left
+               v3s16(1,0,0), // right
                v3s16(0,-1,0), // bottom
        };
 
        recursion_depth++;
 
        v3s16 p;
+       bool from_ocean = false;
        
        // Randomize horizontal order
        static s32 cs = 0;
@@ -622,10 +587,10 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
        //dstream<<"s1="<<s1<<", s2="<<s2<<std::endl;
 
        {
-       TimeTaker timer1("flowWater pre", g_device, &flowwater_pre_time);
+       TimeTaker timer1("flowWater pre", &flowwater_pre_time);
        
        // Load neighboring nodes
-       emerge(VoxelArea(removed_pos - v3s16(1,1,1), removed_pos + v3s16(1,1,1)));
+       emerge(VoxelArea(removed_pos - v3s16(1,1,1), removed_pos + v3s16(1,1,1)), 4);
        
        // Ignore incorrect removed_pos
        {
@@ -634,14 +599,18 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
                if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED))
                        return false;
                MapNode &n = m_data[m_area.index(removed_pos)];
-               // Water can move only to air
-               if(n.d != MATERIAL_AIR)
+               // Ignore nodes to which the water can't go
+               if(liquid_replaces_content(n.d) == false)
                        return false;
        }
        
        s32 i;
        for(i=0; i<6; i++)
        {
+               // Don't raise water from bottom
+               if(m_disable_water_climb && i == 5)
+                       continue;
+
                p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z);
 
                u8 f = m_flags[m_area.index(p)];
@@ -650,7 +619,7 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
                        continue;
                MapNode &n = m_data[m_area.index(p)];
                // Only liquid nodes can move
-               if(material_liquid(n.d) == false)
+               if(content_liquid(n.d) == false)
                        continue;
                // If block is at top, select it always
                if(i == 0)
@@ -660,11 +629,13 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
                // If block is at bottom, select it if it has enough pressure
                if(i == 5)
                {
+                       //if(n.pressure >= PRESERVE_WATER_VOLUME ? 3 : 2)
                        if(n.pressure >= 3)
                                break;
                        continue;
                }
                // Else block is at some side. Select it if it has enough pressure
+               //if(n.pressure >= PRESERVE_WATER_VOLUME ? 2 : 1)
                if(n.pressure >= 2)
                {
                        break;
@@ -675,22 +646,56 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
        if(i==6)
                return false;
 
-       // Switch nodes at p and removed_pos
+       /*
+               Move water and bubble
+       */
+
        u8 m = m_data[m_area.index(p)].d;
        u8 f = m_flags[m_area.index(p)];
-       m_data[m_area.index(p)].d = m_data[m_area.index(removed_pos)].d;
-       m_flags[m_area.index(p)] = m_flags[m_area.index(removed_pos)];
+
+       if(m == CONTENT_WATERSOURCE)
+               from_ocean = true;
+
+       // Move air bubble if not taking water from ocean
+       if(from_ocean == false)
+       {
+               m_data[m_area.index(p)].d = m_data[m_area.index(removed_pos)].d;
+               m_flags[m_area.index(p)] = m_flags[m_area.index(removed_pos)];
+       }
+       
+       /*
+               This has to be done to copy the brightness of a light source
+               correctly. Otherwise unspreadLight will fuck up when water
+               has replaced a light source.
+       */
+       u8 light = m_data[m_area.index(removed_pos)].getLightBanksWithSource();
+
        m_data[m_area.index(removed_pos)].d = m;
        m_flags[m_area.index(removed_pos)] = f;
 
+       m_data[m_area.index(removed_pos)].setLightBanks(light);
+       
        // Mark removed_pos checked
        m_flags[m_area.index(removed_pos)] |= VOXELFLAG_CHECKED;
+
        // If block was dropped from surface, increase pressure
        if(i == 0 && m_data[m_area.index(removed_pos)].pressure == 1)
        {
                m_data[m_area.index(removed_pos)].pressure = 2;
        }
        
+       /*
+       NOTE: This does not work as-is
+       if(m == CONTENT_WATERSOURCE)
+       {
+               // If block was raised to surface, increase pressure of
+               // source node
+               if(i == 5 && m_data[m_area.index(p)].pressure == 1)
+               {
+                       m_data[m_area.index(p)].pressure = 2;
+               }
+       }*/
+       
        /*if(debugprint)
        {
                dstream<<"VoxelManipulator::flowWater(): Moved bubble:"<<std::endl;
@@ -720,16 +725,40 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
        }
        
        }//timer1
-
-       // Flow water to the newly created empty position
-       flowWater(p, active_nodes, recursion_depth,
-                       debugprint, counter, counterlimit);
+       
+       //if(PRESERVE_WATER_VOLUME)
+       if(from_ocean == false)
+       {
+               // Flow water to the newly created empty position
+               /*flowWater(p, active_nodes, recursion_depth,
+                               debugprint, counter, counterlimit);*/
+               flowWater(p, active_nodes, recursion_depth,
+                               debugprint, stoptime);
+       }
+       
+       if(stoptime != 0)
+       {
+               u32 timenow = getTimeMs();
+               // Well, it is a bit hard to guess because we don't know the
+               // start time...
+               bool overflow = timenow < stoptime - 100000;
+               if(timenow >= stoptime || overflow)
+               {
+                       dstream<<"flowWater: stoptime reached"<<std::endl;
+                       throw ProcessingLimitException("flowWater stoptime reached");
+               }
+       }
        
 find_again:
+       
        // Try flowing water to empty positions around removed_pos.
        // They are checked in reverse order compared to the previous loop.
        for(s32 i=5; i>=0; i--)
        {
+               // Don't try to flow to top
+               if(m_disable_water_climb && i == 0)
+                       continue;
+
                //v3s16 p = removed_pos + dirs[i];
                p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z);
 
@@ -739,13 +768,15 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
                        continue;
                MapNode &n = m_data[m_area.index(p)];
                // Water can only move to air
-               if(n.d != MATERIAL_AIR)
+               if(liquid_replaces_content(n.d) == false)
                        continue;
                        
                // Flow water to node
                bool moved =
                flowWater(p, active_nodes, recursion_depth,
-                               debugprint, counter, counterlimit);
+                               debugprint, stoptime);
+               /*flowWater(p, active_nodes, recursion_depth,
+                               debugprint, counter, counterlimit);*/
                
                if(moved)
                {
@@ -754,27 +785,13 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos,
                }
        }
 
-       if(counter != NULL)
-       {
-               (*counter)++;
-               if((*counter) % 10 == 0)
-                       dstream<<"flowWater(): moved "<<(*counter)<<" nodes"
-                                       <<std::endl;
-
-               if(counterlimit != -1 && (*counter) > counterlimit)
-               {
-                       dstream<<"Counter limit reached; returning"<<std::endl;
-                       throw ProcessingLimitException("flowWater counterlimit reached");
-               }
-       }
-       
        return true;
 }
 
 void VoxelManipulator::flowWater(
                core::map<v3s16, u8> &active_nodes,
                int recursion_depth, bool debugprint,
-               int counterlimit)
+               u32 timelimit)
 {
        addarea_time = 0;
        emerge_time = 0;
@@ -783,25 +800,49 @@ void VoxelManipulator::flowWater(
        updateareawaterpressure_time = 0;
        flowwater_pre_time = 0;
 
-       TimeTaker timer1("flowWater (active_nodes)", g_device);
+       if(active_nodes.size() == 0)
+       {
+               dstream<<"flowWater: no active nodes"<<std::endl;
+               return;
+       }
+
+       //TimeTaker timer1("flowWater (active_nodes)", g_irrlicht);
+
+       //dstream<<"active_nodes.size() = "<<active_nodes.size()<<std::endl;
 
-       dstream<<"active_nodes.size() = "<<active_nodes.size()<<std::endl;
 
-       int counter = 0;
+       u32 stoptime = 0;
+       stoptime = getTimeMs() + timelimit;
+
+       // Count of handled active nodes
+       u32 handled_count = 0;
 
        try
        {
 
+       /*
+               Take random one at first
+
+               This is randomized only at the first time so that all
+               subsequent nodes will be taken at roughly the same position
+       */
+       s32 k = 0;
+       if(active_nodes.size() != 0)
+               k = (s32)myrand() % (s32)active_nodes.size();
+
        // Flow water to active nodes
        for(;;)
+       //for(s32 h=0; h<1; h++)
        {
-               // Clear check flags
-               clearFlag(VOXELFLAG_CHECKED);
-               
                if(active_nodes.size() == 0)
                        break;
 
-               dstream<<"Selecting a new active_node"<<std::endl;
+               handled_count++;
+               
+               // Clear check flags
+               clearFlag(VOXELFLAG_CHECKED);
+               
+               //dstream<<"Selecting a new active_node"<<std::endl;
 
 #if 0
                // Take first one
@@ -810,9 +851,7 @@ void VoxelManipulator::flowWater(
 #endif
 
 #if 1
-               // Take random one
-               s32 k = (s32)rand() % (s32)active_nodes.size();
-               //s32 k = 0;
+               
                core::map<v3s16, u8>::Iterator
                                i = active_nodes.getIterator().getNode();
                for(s32 j=0; j<k; j++)
@@ -820,12 +859,17 @@ void VoxelManipulator::flowWater(
                        i++;
                }
                core::map<v3s16, u8>::Node *n = i.getNode();
+
+               // Decrement index if less than 0.
+               // This keeps us in existing indices always.
+               if(k > 0)
+                       k--;
 #endif
 
                v3s16 p = n->getKey();
                active_nodes.remove(p);
                flowWater(p, active_nodes, recursion_depth,
-                               debugprint, &counter, counterlimit);
+                               debugprint, stoptime);
        }
 
        }
@@ -834,20 +878,21 @@ void VoxelManipulator::flowWater(
                //dstream<<"getWaterPressure ProcessingLimitException"<<std::endl;
        }
        
-       v3s16 e = m_area.getExtent();
+       /*v3s16 e = m_area.getExtent();
        s32 v = m_area.getVolume();
-       dstream<<"flowWater (active): moved "<<counter<<" nodes, "
+       dstream<<"flowWater (active): "
                        <<"area ended up as "
                        <<e.X<<"x"<<e.Y<<"x"<<e.Z<<" = "<<v
+                       <<", handled a_node count: "<<handled_count
+                       <<", active_nodes.size() = "<<active_nodes.size()
                        <<std::endl;
-       
        dstream<<"addarea_time: "<<addarea_time
                        <<", emerge_time: "<<emerge_time
                        <<", emerge_load_time: "<<emerge_load_time
                        <<", clearflag_time: "<<clearflag_time
                        <<", flowwater_pre_time: "<<flowwater_pre_time
                        <<", updateareawaterpressure_time: "<<updateareawaterpressure_time
-                       <<std::endl;
+                       <<std::endl;*/
 }