Merge branch 'upstream/master'
authorNils Dagsson Moskopp <nils@dieweltistgarnichtso.net>
Wed, 20 Jul 2011 12:20:07 +0000 (14:20 +0200)
committerNils Dagsson Moskopp <nils@dieweltistgarnichtso.net>
Wed, 20 Jul 2011 12:20:07 +0000 (14:20 +0200)
1  2 
src/map.cpp

diff --combined src/map.cpp
index aa064637f995b4b7bf77544aa4ae075157c6d298,9ff0fa6d32546d29c1aeea278d7bd5fe49ea6ce9..e47b1b212c44de752af391e60da26ed25a9c46ec
@@@ -1086,7 -1086,7 +1086,7 @@@ void Map::addNodeAndUpdate(v3s16 p, Map
                v3s16 p2 = p + dirs[i];
  
                MapNode n2 = getNode(p2);
 -              if(content_liquid(n2.d))
 +              if(content_liquid(n2.d) || n2.d == CONTENT_AIR)
                {
                        m_transforming_liquid.push_back(p2);
                }
@@@ -1240,19 -1240,17 +1240,19 @@@ void Map::removeNodeAndUpdate(v3s16 p
        }
  
        /*
 -              Add neighboring liquid nodes to transform queue.
 +              Add neighboring liquid nodes and this node to transform queue.
 +              (it's vital for the node itself to get updated last.)
        */
 -      v3s16 dirs[6] = {
 +      v3s16 dirs[7] = {
                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
 +              v3s16(0,0,0), // self
        };
 -      for(u16 i=0; i<6; i++)
 +      for(u16 i=0; i<7; i++)
        {
                try
                {
                v3s16 p2 = p + dirs[i];
  
                MapNode n2 = getNode(p2);
 -              if(content_liquid(n2.d))
 +              if(content_liquid(n2.d) || n2.d == CONTENT_AIR)
                {
                        m_transforming_liquid.push_back(p2);
                }
@@@ -1540,17 -1538,6 +1540,17 @@@ void Map::PrintInfo(std::ostream &out
  
  #define WATER_DROP_BOOST 4
  
 +enum NeighborType {
 +      NEIGHBOR_UPPER,
 +      NEIGHBOR_SAME_LEVEL,
 +      NEIGHBOR_LOWER
 +};
 +struct NodeNeighbor {
 +      MapNode n;
 +      NeighborType t;
 +      v3s16 p;
 +};
 +
  void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
  {
        DSTACK(__FUNCTION_NAME);
                v3s16 p0 = m_transforming_liquid.pop_front();
  
                MapNode n0 = getNodeNoEx(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++)
 -                      {
 -                              bool from_top = (i==0);
 -
 -                              v3s16 p2 = p0 + dirs_from[i];
 -                              MapNode n2 = getNodeNoEx(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;
 +                      Collect information about current node
 +               */
 +              s8 liquid_level = -1;
 +              u8 liquid_kind = CONTENT_IGNORE;
 +              LiquidType liquid_type = content_features(n0.d).liquid_type;
 +              switch (liquid_type) {
 +                      case LIQUID_SOURCE:
 +                              liquid_level = 8;
 +                              liquid_kind = content_features(n0.d).liquid_alternative_flowing;
 +                              break;
 +                      case LIQUID_FLOWING:
 +                              liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
 +                              liquid_kind = n0.d;
 +                              break;
 +                      case LIQUID_NONE:
 +                              // if this is an air node, it *could* be transformed into a liquid. otherwise,
 +                              // continue with the next node.
 +                              if (n0.d != CONTENT_AIR)
 +                                      continue;
 +                              liquid_kind = CONTENT_AIR;
 +                              break;
 +              }
 +              
 +              /*
 +                      Collect information about the environment
 +               */
 +              v3s16 dirs[6] = {
 +                      v3s16( 0, 1, 0), // top
 +                      v3s16( 0,-1, 0), // bottom
 +                      v3s16( 1, 0, 0), // right
 +                      v3s16(-1, 0, 0), // left
 +                      v3s16( 0, 0, 1), // back
 +                      v3s16( 0, 0,-1), // front
 +              };
 +              NodeNeighbor sources[6]; // surrounding sources
 +              int num_sources = 0;
 +              NodeNeighbor flows[6]; // surrounding flowing liquid nodes
 +              int num_flows = 0;
 +              NodeNeighbor airs[6]; // surrounding air
 +              int num_airs = 0;
 +              NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid
 +              int num_neutrals = 0;
 +              bool flowing_down = false;
 +              for (u16 i = 0; i < 6; i++) {
 +                      NeighborType nt = NEIGHBOR_SAME_LEVEL;
 +                      switch (i) {
 +                              case 0:
 +                                      nt = NEIGHBOR_UPPER;
 +                                      break;
 +                              case 1:
 +                                      nt = NEIGHBOR_LOWER;
 +                                      break;
 +                      }
 +                      v3s16 npos = p0 + dirs[i];
 +                      NodeNeighbor nb = {getNodeNoEx(npos), nt, npos};
 +                      switch (content_features(nb.n.d).liquid_type) {
 +                              case LIQUID_NONE:
 +                                      if (nb.n.d == CONTENT_AIR) {
 +                                              airs[num_airs++] = nb;
 +                                              // if the current node happens to be a flowing node, it will start to flow down here.
 +                                              if (nb.t == NEIGHBOR_LOWER)
 +                                                      flowing_down = true;
 +                                      } else {
 +                                              neutrals[num_neutrals++] = nb;
                                        }
 -                                      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;
 +                                      break;
 +                              case LIQUID_SOURCE:
 +                                      // if this node is not (yet) of a liquid type, choose the first liquid type we encounter 
 +                                      if (liquid_kind == CONTENT_AIR)
 +                                              liquid_kind = content_features(nb.n.d).liquid_alternative_flowing;
 +                                      if (content_features(nb.n.d).liquid_alternative_flowing !=liquid_kind) {
 +                                              neutrals[num_neutrals++] = nb;
 +                                      } else {
 +                                              sources[num_sources++] = nb;
                                        }
 -                                      else if(n2_liquid_level > 0)
 -                                      {
 -                                              new_liquid_level = n2_liquid_level - 1;
 +                                      break;
 +                              case LIQUID_FLOWING:
 +                                      // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
 +                                      if (liquid_kind == CONTENT_AIR)
 +                                              liquid_kind = content_features(nb.n.d).liquid_alternative_flowing;
 +                                      if (content_features(nb.n.d).liquid_alternative_flowing != liquid_kind) {
 +                                              neutrals[num_neutrals++] = nb;
 +                                      } else {
 +                                              flows[num_flows++] = nb;
 +                                              if (nb.t == NEIGHBOR_LOWER)
 +                                                      flowing_down = true;
                                        }
 -
 -                                      if(new_liquid_level > new_liquid_level_max)
 -                                              new_liquid_level_max = new_liquid_level;
 -                              }
 -                      } //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);
 +                                      break;
 +                      }
 +              }
 +              
 +              /*
 +                      decide on the type (and possibly level) of the current node
 +               */
 +              u8 new_node_content;
 +              s8 new_node_level = -1;
 +              if (num_sources >= 2 || liquid_type == LIQUID_SOURCE) {
 +                      // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
 +                      // or the flowing alternative of the first of the surrounding sources (if it's air), so
 +                      // it's perfectly safe to use liquid_kind here to determine the new node content.
 +                      new_node_content = content_features(liquid_kind).liquid_alternative_source;
 +              } else if (num_sources == 1 && sources[0].t != NEIGHBOR_LOWER) {
 +                      // liquid_kind is set properly, see above
 +                      new_node_content = liquid_kind;
 +                      new_node_level = 7;
 +              } else {
 +                      // no surrounding sources, so get the maximum level that can flow into this node
 +                      for (u16 i = 0; i < num_flows; i++) {
 +                              u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
 +                              switch (flows[i].t) {
 +                                      case NEIGHBOR_UPPER:
 +                                              if (nb_liquid_level + WATER_DROP_BOOST > new_node_level) {
 +                                                      new_node_level = 7;
 +                                                      if (nb_liquid_level + WATER_DROP_BOOST < 7)
 +                                                              new_node_level = nb_liquid_level + WATER_DROP_BOOST;
 +                                              }
 +                                              break;
 +                                      case NEIGHBOR_LOWER:
 +                                              break;
 +                                      case NEIGHBOR_SAME_LEVEL:
 +                                              if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
 +                                                      nb_liquid_level > 0 && nb_liquid_level - 1 > new_node_level) {
 +                                                      new_node_level = nb_liquid_level - 1;
 +                                              }
 +                                              break;
                                }
 -
 -                              /*
 -                                      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++)
 -                              {
 -                                      v3s16 p2 = p0 + dirs[i];
 -
 -                                      MapNode n2 = getNodeNoEx(p2);
 -                                      if(content_flowing_liquid(n2.d))
 -                                      {
 -                                              m_transforming_liquid.push_back(p2);
 +                      }
 +                      // don't flow as far in open terrain - if there isn't at least one adjacent solid block,
 +                      // substract another unit from the resulting water level.
 +                      if (!flowing_down && new_node_level >= 1) {
 +                              bool at_wall = false;
 +                              for (u16 i = 0; i < num_neutrals; i++) {
 +                                      if (neutrals[i].t == NEIGHBOR_SAME_LEVEL) {
 +                                              at_wall = true;
 +                                              break;
                                        }
                                }
 +                              if (!at_wall)
 +                                      new_node_level -= 1;
                        }
 +                      
 +                      if (new_node_level >= 0)
 +                              new_node_content = liquid_kind;
 +                      else
 +                              new_node_content = CONTENT_AIR;
                }
 -
 -              // Get a new one from queue if the node has turned into non-water
 -              if(content_liquid(n0.d) == false)
 +              
 +              /*
 +                      check if anything has changed. if not, just continue with the next node.
 +               */
 +              if (new_node_content == n0.d && (content_features(n0.d).liquid_type != LIQUID_FLOWING ||
 +                                                                               ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
 +                                                                               ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
 +                                                                               == flowing_down)))
                        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++)
 -              {
 -                      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 = getNodeNoEx(p2);
 -                      //dstream<<"[1] n2.param="<<(int)n2.param<<std::endl;
 -
 -                      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;
 +                      update the current node
 +               */
 +              bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
 +              n0.d = new_node_content;
 +              if (content_features(n0.d).liquid_type == LIQUID_FLOWING) {
 +                      // set level to last 3 bits, flowing down bit to 4th bit
 +                      n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
 +              } else {
 +                      n0.param2 = 0;
 +              }
 +              setNode(p0, n0);
 +              v3s16 blockpos = getNodeBlockPos(p0);
 +              MapBlock *block = getBlockNoCreateNoEx(blockpos);
 +              if(block != NULL)
 +                      modified_blocks.insert(blockpos, block);
 +              
 +              /*
 +                      enqueue neighbors for update if neccessary
 +               */
 +              switch (content_features(n0.d).liquid_type) {
 +                      case LIQUID_SOURCE:
 +                              // make sure source flows into all neighboring nodes
 +                              for (u16 i = 0; i < num_flows; i++)
 +                                      if (flows[i].t != NEIGHBOR_UPPER)
 +                                              m_transforming_liquid.push_back(flows[i].p);
 +                              for (u16 i = 0; i < num_airs; i++)
 +                                      if (airs[i].t != NEIGHBOR_UPPER)
 +                                              m_transforming_liquid.push_back(airs[i].p);
 +                              break;
 +                      case LIQUID_NONE:
 +                              // this flow has turned to air; neighboring flows might need to do the same
 +                              for (u16 i = 0; i < num_flows; i++)
 +                                      m_transforming_liquid.push_back(flows[i].p);
 +                              break;
 +                      case LIQUID_FLOWING:
 +                              for (u16 i = 0; i < num_flows; i++) {
 +                                      u8 flow_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
 +                                      // liquid_level is still the ORIGINAL level of this node.
 +                                      if (flows[i].t != NEIGHBOR_UPPER && ((flow_level < liquid_level || flow_level < new_node_level) ||
 +                                              flow_down_enabled))
 +                                              m_transforming_liquid.push_back(flows[i].p);
                                }
 -                              else
 -                              {
 -                                      if(liquid_next_level > liquid_level)
 -                                      {
 -                                              n2.param2 = liquid_next_level;
 -                                              setNode(p2, n2);
 -
 -                                              n2_changed = true;
 -                                              flowed = true;
 -                                      }
 +                              for (u16 i = 0; i < num_airs; i++) {
 +                                      if (airs[i].t != NEIGHBOR_UPPER && (airs[i].t == NEIGHBOR_LOWER || new_node_level > 0))
 +                                              m_transforming_liquid.push_back(airs[i].p);
                                }
 -                      }
 -                      else if(n2.d == CONTENT_AIR)
 -                      {
 -                              n2.d = nonsource_c;
 -                              n2.param2 = liquid_next_level;
 -                              setNode(p2, n2);
 -
 -                              n2_changed = true;
 -                              flowed = true;
 -                      }
 -
 -                      //dstream<<"[2] n2.param="<<(int)n2.param<<std::endl;
 -
 -                      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 && !is_source)
                                break;
                }
 -
 +              
                loopcount++;
                //if(loopcount >= 100000)
 -              if(loopcount >= initial_size * 1)
 +              if(loopcount >= initial_size * 10) {
                        break;
 +              }
        }
        //dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
  }
@@@ -2026,9 -2033,14 +2026,14 @@@ void ServerMap::initBlockMake(mapgen::B
  
                        for(s16 y=-1; y<=1; y++)
                        {
-                               MapBlock *block = createBlock(blockpos);
+                               //MapBlock *block = createBlock(blockpos);
+                               // 1) get from memory, 2) load from disk
+                               MapBlock *block = emergeBlock(blockpos, false);
+                               // 3) create a blank one
+                               if(block == NULL)
+                                       block = createBlock(blockpos);
  
-                               // Lighting won't be calculated
+                               // Lighting will not be valid after make_chunk is called
                                block->setLightingExpired(true);
                                // Lighting will be calculated
                                //block->setLightingExpired(false);
@@@ -2145,10 -2157,18 +2150,18 @@@ MapBlock* ServerMap::finishBlockMake(ma
                TimeTaker t("finishBlockMake lighting update");
  
                core::map<v3s16, MapBlock*> lighting_update_blocks;
+ #if 1
                // Center block
                lighting_update_blocks.insert(block->getPos(), block);
-       #if 0
+ #endif
+ #if 0
                // All modified blocks
+               // NOTE: Should this be done? If this is not done, then the lighting
+               // of the others will be updated in a different place, one by one, i
+               // think... or they might not? Well, at least they are left marked as
+               // "lighting expired"; it seems that is not handled at all anywhere,
+               // so enabling this will slow it down A LOT because otherwise it
+               // would not do this at all. This causes the black trees.
                for(core::map<v3s16, MapBlock*>::Iterator
                                i = changed_blocks.getIterator();
                                i.atEnd() == false; i++)
                        lighting_update_blocks.insert(i.getNode()->getKey(),
                                        i.getNode()->getValue());
                }
      #endif
+ #endif
                updateLighting(lighting_update_blocks, changed_blocks);
  
                if(enable_mapgen_debug_info == false)