Lighting: Update lighting at block loading
authorDániel Juhász <juhdanad@gmail.com>
Thu, 27 Oct 2016 21:25:44 +0000 (23:25 +0200)
committerparamat <mat.gregory@virginmedia.com>
Mon, 13 Feb 2017 00:05:49 +0000 (00:05 +0000)
This commit updates mapblocks' light if necessary when they are loaded.
This removes ghost lighting.

src/clientiface.cpp
src/map.cpp
src/mapblock.cpp
src/mapblock.h
src/serialization.h
src/voxelalgorithms.cpp
src/voxelalgorithms.h

index 47730343c60ed4fb6d36bd925d69b4f45ade67a8..0eb68c9c12295061b044926f12f9971611d2d892 100644 (file)
@@ -283,12 +283,6 @@ void RemoteClient::GetNextBlocks (
                                        surely_not_found_on_disk = true;
                                }
 
-                               // Block is valid if lighting is up-to-date and data exists
-                               if(block->isValid() == false)
-                               {
-                                       block_is_invalid = true;
-                               }
-
                                if(block->isGenerated() == false)
                                        block_is_invalid = true;
 
index f2a4b7ffec02157e5188e0b3346c57dd76ab85ef..ffba772620e6576a7f777b5066dff6a192f13323 100644 (file)
@@ -824,7 +824,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
        // Update lighting
        std::vector<std::pair<v3s16, MapNode> > oldnodes;
        oldnodes.push_back(std::pair<v3s16, MapNode>(p, oldnode));
-       voxalgo::update_lighting_nodes(this, m_nodedef, oldnodes, modified_blocks);
+       voxalgo::update_lighting_nodes(this, oldnodes, modified_blocks);
 
        for(std::map<v3s16, MapBlock*>::iterator
                        i = modified_blocks.begin();
@@ -1523,7 +1523,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
        for (std::deque<v3s16>::iterator iter = must_reflow.begin(); iter != must_reflow.end(); ++iter)
                m_transforming_liquid.push_back(*iter);
 
-       voxalgo::update_lighting_nodes(this, m_nodedef, changed_nodes, modified_blocks);
+       voxalgo::update_lighting_nodes(this, changed_nodes, modified_blocks);
 
 
        /* ----------------------------------------------------------------------
@@ -1955,27 +1955,10 @@ void ServerMap::finishBlockMake(BlockMakeData *data,
        v3s16 bpmax = data->blockpos_max;
 
        v3s16 extra_borders(1, 1, 1);
-       v3s16 full_bpmin = bpmin - extra_borders;
-       v3s16 full_bpmax = bpmax + extra_borders;
 
        bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
        EMERGE_DBG_OUT("finishBlockMake(): " PP(bpmin) " - " PP(bpmax));
 
-       /*
-               Set lighting to non-expired state in all of them.
-               This is cheating, but it is not fast enough if all of them
-               would actually be updated.
-       */
-       for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++)
-       for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++)
-       for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) {
-               MapBlock *block = emergeBlock(v3s16(x, y, z), false);
-               if (!block)
-                       continue;
-
-               block->setLightingExpired(false);
-       }
-
        /*
                Blit generated stuff to map
                NOTE: blitBackAll adds nearly everything to changed_blocks
@@ -2991,7 +2974,6 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool
 
                // We just loaded it from, so it's up-to-date.
                block->resetModified();
-
        }
        catch(SerializationError &e)
        {
@@ -3015,71 +2997,80 @@ MapBlock* ServerMap::loadBlock(v3s16 blockpos)
 {
        DSTACK(FUNCTION_NAME);
 
+       bool created_new = (getBlockNoCreateNoEx(blockpos) == NULL);
+
        v2s16 p2d(blockpos.X, blockpos.Z);
 
        std::string ret;
        dbase->loadBlock(blockpos, &ret);
        if (ret != "") {
                loadBlock(&ret, blockpos, createSector(p2d), false);
-               return getBlockNoCreateNoEx(blockpos);
-       }
-       // Not found in database, try the files
-
-       // The directory layout we're going to load from.
-       //  1 - original sectors/xxxxzzzz/
-       //  2 - new sectors2/xxx/zzz/
-       //  If we load from anything but the latest structure, we will
-       //  immediately save to the new one, and remove the old.
-       int loadlayout = 1;
-       std::string sectordir1 = getSectorDir(p2d, 1);
-       std::string sectordir;
-       if(fs::PathExists(sectordir1))
-       {
-               sectordir = sectordir1;
-       }
-       else
-       {
-               loadlayout = 2;
-               sectordir = getSectorDir(p2d, 2);
-       }
+       } else {
+               // Not found in database, try the files
+
+               // The directory layout we're going to load from.
+               //  1 - original sectors/xxxxzzzz/
+               //  2 - new sectors2/xxx/zzz/
+               //  If we load from anything but the latest structure, we will
+               //  immediately save to the new one, and remove the old.
+               int loadlayout = 1;
+               std::string sectordir1 = getSectorDir(p2d, 1);
+               std::string sectordir;
+               if (fs::PathExists(sectordir1)) {
+                       sectordir = sectordir1;
+               } else {
+                       loadlayout = 2;
+                       sectordir = getSectorDir(p2d, 2);
+               }
 
-       /*
+               /*
                Make sure sector is loaded
-       */
+                */
 
-       MapSector *sector = getSectorNoGenerateNoEx(p2d);
-       if(sector == NULL)
-       {
-               try{
-                       sector = loadSectorMeta(sectordir, loadlayout != 2);
-               }
-               catch(InvalidFilenameException &e)
-               {
-                       return NULL;
-               }
-               catch(FileNotGoodException &e)
-               {
-                       return NULL;
-               }
-               catch(std::exception &e)
-               {
-                       return NULL;
+               MapSector *sector = getSectorNoGenerateNoEx(p2d);
+               if (sector == NULL) {
+                       try {
+                               sector = loadSectorMeta(sectordir, loadlayout != 2);
+                       } catch(InvalidFilenameException &e) {
+                               return NULL;
+                       } catch(FileNotGoodException &e) {
+                               return NULL;
+                       } catch(std::exception &e) {
+                               return NULL;
+                       }
                }
-       }
 
-       /*
+
+               /*
                Make sure file exists
-       */
+                */
 
-       std::string blockfilename = getBlockFilename(blockpos);
-       if(fs::PathExists(sectordir + DIR_DELIM + blockfilename) == false)
-               return NULL;
+               std::string blockfilename = getBlockFilename(blockpos);
+               if (fs::PathExists(sectordir + DIR_DELIM + blockfilename) == false)
+                       return NULL;
 
-       /*
+               /*
                Load block and save it to the database
-       */
-       loadBlock(sectordir, blockfilename, sector, true);
-       return getBlockNoCreateNoEx(blockpos);
+                */
+               loadBlock(sectordir, blockfilename, sector, true);
+       }
+       MapBlock *block = getBlockNoCreateNoEx(blockpos);
+       if (created_new && (block != NULL)) {
+               std::map<v3s16, MapBlock*> modified_blocks;
+               // Fix lighting if necessary
+               voxalgo::update_block_border_lighting(this, block, modified_blocks);
+               if (!modified_blocks.empty()) {
+                       //Modified lighting, send event
+                       MapEditEvent event;
+                       event.type = MEET_OTHER;
+                       std::map<v3s16, MapBlock *>::iterator it;
+                       for (it = modified_blocks.begin();
+                                       it != modified_blocks.end(); ++it)
+                               event.modified_blocks.insert(it->first);
+                       dispatchEvent(&event);
+               }
+       }
+       return block;
 }
 
 bool ServerMap::deleteBlock(v3s16 blockpos)
index f8c3197bc61405a706c0948c807292d4d3339995..840cb9b3994a28da789db0f898433e8da1cc49dd 100644 (file)
@@ -73,7 +73,7 @@ MapBlock::MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy):
                m_modified(MOD_STATE_WRITE_NEEDED),
                m_modified_reason(MOD_REASON_INITIAL),
                is_underground(false),
-               m_lighting_expired(true),
+               m_lighting_complete(0xFFFF),
                m_day_night_differs(false),
                m_day_night_differs_expired(true),
                m_generated(false),
@@ -571,11 +571,12 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
                flags |= 0x01;
        if(getDayNightDiff())
                flags |= 0x02;
-       if(m_lighting_expired)
-               flags |= 0x04;
        if(m_generated == false)
                flags |= 0x08;
        writeU8(os, flags);
+       if (version >= 27) {
+               writeU16(os, m_lighting_complete);
+       }
 
        /*
                Bulk node data
@@ -672,7 +673,11 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
        u8 flags = readU8(is);
        is_underground = (flags & 0x01) ? true : false;
        m_day_night_differs = (flags & 0x02) ? true : false;
-       m_lighting_expired = (flags & 0x04) ? true : false;
+       if (version < 27) {
+               m_lighting_complete = 0xFFFF;
+       } else {
+               m_lighting_complete = readU16(is);
+       }
        m_generated = (flags & 0x08) ? false : true;
 
        /*
@@ -783,7 +788,7 @@ void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk)
        // Initialize default flags
        is_underground = false;
        m_day_night_differs = false;
-       m_lighting_expired = false;
+       m_lighting_complete = 0xFFFF;
        m_generated = true;
 
        // Make a temporary buffer
@@ -849,7 +854,6 @@ void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk)
                is.read((char*)&flags, 1);
                is_underground = (flags & 0x01) ? true : false;
                m_day_night_differs = (flags & 0x02) ? true : false;
-               m_lighting_expired = (flags & 0x04) ? true : false;
                if(version >= 18)
                        m_generated = (flags & 0x08) ? false : true;
 
@@ -1027,10 +1031,7 @@ std::string analyze_block(MapBlock *block)
        else
                desc<<"is_ug [ ], ";
 
-       if(block->getLightingExpired())
-               desc<<"lighting_exp [X], ";
-       else
-               desc<<"lighting_exp [ ], ";
+       desc<<"lighting_complete: "<<block->getLightingComplete()<<", ";
 
        if(block->isDummy())
        {
index f808001094240a49c6d8f90d9f9a00354633b5c7..5a0ec937ade1eb15a7b693638fb5aa254deae414 100644 (file)
@@ -105,7 +105,7 @@ public:
 #define MOD_REASON_INITIAL                   (1 << 0)
 #define MOD_REASON_REALLOCATE                (1 << 1)
 #define MOD_REASON_SET_IS_UNDERGROUND        (1 << 2)
-#define MOD_REASON_SET_LIGHTING_EXPIRED      (1 << 3)
+#define MOD_REASON_SET_LIGHTING_COMPLETE     (1 << 3)
 #define MOD_REASON_SET_GENERATED             (1 << 4)
 #define MOD_REASON_SET_NODE                  (1 << 5)
 #define MOD_REASON_SET_NODE_NO_CHECK         (1 << 6)
@@ -213,17 +213,42 @@ public:
                raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_IS_UNDERGROUND);
        }
 
-       inline void setLightingExpired(bool expired)
+       inline void setLightingComplete(u16 newflags)
        {
-               if (expired != m_lighting_expired){
-                       m_lighting_expired = expired;
-                       raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_LIGHTING_EXPIRED);
+               if (newflags != m_lighting_complete) {
+                       m_lighting_complete = newflags;
+                       raiseModified(MOD_STATE_WRITE_NEEDED, MOD_REASON_SET_LIGHTING_COMPLETE);
                }
        }
 
-       inline bool getLightingExpired()
+       inline u16 getLightingComplete()
        {
-               return m_lighting_expired;
+               return m_lighting_complete;
+       }
+
+       inline void setLightingComplete(LightBank bank, u8 direction,
+               bool is_complete)
+       {
+               assert(direction >= 0 && direction <= 5);
+               if (bank == LIGHTBANK_NIGHT) {
+                       direction += 6;
+               }
+               u16 newflags = m_lighting_complete;
+               if (is_complete) {
+                       newflags |= 1 << direction;
+               } else {
+                       newflags &= ~(1 << direction);
+               }
+               setLightingComplete(newflags);
+       }
+
+       inline bool isLightingComplete(LightBank bank, u8 direction)
+       {
+               assert(direction >= 0 && direction <= 5);
+               if (bank == LIGHTBANK_NIGHT) {
+                       direction += 6;
+               }
+               return (m_lighting_complete & (1 << direction)) != 0;
        }
 
        inline bool isGenerated()
@@ -239,15 +264,6 @@ public:
                }
        }
 
-       inline bool isValid()
-       {
-               if (m_lighting_expired)
-                       return false;
-               if (data == NULL)
-                       return false;
-               return true;
-       }
-
        ////
        //// Position stuff
        ////
@@ -613,14 +629,14 @@ private:
        */
        bool is_underground;
 
-       /*
-               Set to true if changes has been made that make the old lighting
-               values wrong but the lighting hasn't been actually updated.
-
-               If this is false, lighting is exactly right.
-               If this is true, lighting might be wrong or right.
+       /*!
+        * Each bit indicates if light spreading was finished
+        * in a direction. (Because the neighbor could also be unloaded.)
+        * Bits: day X+, day Y+, day Z+, day Z-, day Y-, day X-,
+        * night X+, night Y+, night Z+, night Z-, night Y-, night X-,
+        * nothing, nothing, nothing, nothing.
        */
-       bool m_lighting_expired;
+       u16 m_lighting_complete;
 
        // Whether day and night lighting differs
        bool m_day_night_differs;
index 01d37d3632fb0e5f3985d42c0e7737edb59e1c0a..52c63098ee6df9efee2a96b55282b42ef97a6c71 100644 (file)
@@ -62,13 +62,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
        24: 16-bit node ids and node timers (never released as stable)
        25: Improved node timer format
        26: Never written; read the same as 25
+       27: Added light spreading flags to blocks
 */
 // This represents an uninitialized or invalid format
 #define SER_FMT_VER_INVALID 255
 // Highest supported serialization version
-#define SER_FMT_VER_HIGHEST_READ 26
+#define SER_FMT_VER_HIGHEST_READ 27
 // Saved on disk version
-#define SER_FMT_VER_HIGHEST_WRITE 25
+#define SER_FMT_VER_HIGHEST_WRITE 27
 // Lowest supported serialization version
 #define SER_FMT_VER_LOWEST_READ 0
 // Lowest serialization version for writing
index c20917164afb6cdfcdbc89a9b57f4086bbea9a5f..3c32bc125f0b313f3cc73f1b6f9629c52f9c6fbb 100644 (file)
@@ -423,6 +423,7 @@ void unspread_light(Map *map, INodeDefManager *nodemgr, LightBank bank,
                        if (step_rel_block_pos(i, neighbor_rel_pos, neighbor_block_pos)) {
                                neighbor_block = map->getBlockNoCreateNoEx(neighbor_block_pos);
                                if (neighbor_block == NULL) {
+                                       current.block->setLightingComplete(bank, i, false);
                                        continue;
                                }
                        } else {
@@ -486,7 +487,8 @@ void unspread_light(Map *map, INodeDefManager *nodemgr, LightBank bank,
  * \param modified_blocks output, all modified map blocks are added to this
  */
 void spread_light(Map *map, INodeDefManager *nodemgr, LightBank bank,
-       LightQueue &light_sources, std::map<v3s16, MapBlock*> &modified_blocks)
+       LightQueue &light_sources,
+       std::map<v3s16, MapBlock*> &modified_blocks)
 {
        // The light the current node can provide to its neighbors.
        u8 spreading_light;
@@ -511,6 +513,7 @@ void spread_light(Map *map, INodeDefManager *nodemgr, LightBank bank,
                        if (step_rel_block_pos(i, neighbor_rel_pos, neighbor_block_pos)) {
                                neighbor_block = map->getBlockNoCreateNoEx(neighbor_block_pos);
                                if (neighbor_block == NULL) {
+                                       current.block->setLightingComplete(bank, i, false);
                                        continue;
                                }
                        } else {
@@ -584,10 +587,11 @@ bool is_sunlight_above(Map *map, v3s16 pos, INodeDefManager *ndef)
 
 static const LightBank banks[] = { LIGHTBANK_DAY, LIGHTBANK_NIGHT };
 
-void update_lighting_nodes(Map *map, INodeDefManager *ndef,
+void update_lighting_nodes(Map *map,
        std::vector<std::pair<v3s16, MapNode> > &oldnodes,
        std::map<v3s16, MapBlock*> &modified_blocks)
 {
+       INodeDefManager *ndef = map->getNodeDefManager();
        // For node getter functions
        bool is_valid_position;
 
@@ -596,6 +600,22 @@ void update_lighting_nodes(Map *map, INodeDefManager *ndef,
                LightBank bank = banks[i];
                UnlightQueue disappearing_lights(256);
                ReLightQueue light_sources(256);
+               // Nodes that are brighter than the brightest modified node was
+               // won't change, since they didn't get their light from a
+               // modified node.
+               u8 min_safe_light = 0;
+               for (std::vector<std::pair<v3s16, MapNode> >::iterator it =
+                               oldnodes.begin(); it < oldnodes.end(); ++it) {
+                       u8 old_light = it->second.getLight(bank, ndef);
+                       if (old_light > min_safe_light) {
+                               min_safe_light = old_light;
+                       }
+               }
+               // If only one node changed, even nodes with the same brightness
+               // didn't get their light from the changed node.
+               if (oldnodes.size() > 1) {
+                       min_safe_light++;
+               }
                // For each changed node process sunlight and initialize
                for (std::vector<std::pair<v3s16, MapNode> >::iterator it =
                                oldnodes.begin(); it < oldnodes.end(); ++it) {
@@ -634,11 +654,9 @@ void update_lighting_nodes(Map *map, INodeDefManager *ndef,
                                                MapNode n2 = map->getNodeNoEx(p2, &is_valid);
                                                if (is_valid) {
                                                        u8 spread = n2.getLight(bank, ndef);
-                                                       // If the neighbor is at least as bright as
-                                                       // this node then its light is not from
-                                                       // this node.
-                                                       // Its light can spread to this node.
-                                                       if (spread > new_light && spread >= old_light) {
+                                                       // If it is sure that the neighbor won't be
+                                                       // unlighted, its light can spread to this node.
+                                                       if (spread > new_light && spread >= min_safe_light) {
                                                                new_light = spread - 1;
                                                        }
                                                }
@@ -747,6 +765,126 @@ void update_lighting_nodes(Map *map, INodeDefManager *ndef,
        }
 }
 
+/*!
+ * Borders of a map block in relative node coordinates.
+ * Compatible with type 'direction'.
+ */
+const VoxelArea block_borders[] = {
+       VoxelArea(v3s16(15, 0, 0), v3s16(15, 15, 15)), //X+
+       VoxelArea(v3s16(0, 15, 0), v3s16(15, 15, 15)), //Y+
+       VoxelArea(v3s16(0, 0, 15), v3s16(15, 15, 15)), //Z+
+       VoxelArea(v3s16(0, 0, 0), v3s16(15, 15, 0)),   //Z-
+       VoxelArea(v3s16(0, 0, 0), v3s16(15, 0, 15)),   //Y-
+       VoxelArea(v3s16(0, 0, 0), v3s16(0, 15, 15))    //X-
+};
+
+/*!
+ * Returns true if:
+ * -the node has unloaded neighbors
+ * -the node doesn't have light
+ * -the node's light is the same as the maximum of
+ * its light source and its brightest neighbor minus one.
+ * .
+ */
+bool is_light_locally_correct(Map *map, INodeDefManager *ndef, LightBank bank,
+       v3s16 pos)
+{
+       bool is_valid_position;
+       MapNode n = map->getNodeNoEx(pos, &is_valid_position);
+       const ContentFeatures &f = ndef->get(n);
+       if (f.param_type != CPT_LIGHT) {
+               return true;
+       }
+       u8 light = n.getLightNoChecks(bank, &f);
+       assert(f.light_source <= LIGHT_MAX);
+       u8 brightest_neighbor = f.light_source + 1;
+       for (direction d = 0; d < 6; ++d) {
+               MapNode n2 = map->getNodeNoEx(pos + neighbor_dirs[d],
+                       &is_valid_position);
+               u8 light2 = n2.getLight(bank, ndef);
+               if (brightest_neighbor < light2) {
+                       brightest_neighbor = light2;
+               }
+       }
+       assert(light <= LIGHT_SUN);
+       return brightest_neighbor == light + 1;
+}
+
+void update_block_border_lighting(Map *map, MapBlock *block,
+       std::map<v3s16, MapBlock*> &modified_blocks)
+{
+       INodeDefManager *ndef = map->getNodeDefManager();
+       bool is_valid_position;
+       for (s32 i = 0; i < 2; i++) {
+               LightBank bank = banks[i];
+               UnlightQueue disappearing_lights(256);
+               ReLightQueue light_sources(256);
+               // Get incorrect lights
+               for (direction d = 0; d < 6; d++) {
+                       // For each direction
+                       // Get neighbor block
+                       v3s16 otherpos = block->getPos() + neighbor_dirs[d];
+                       MapBlock *other = map->getBlockNoCreateNoEx(otherpos);
+                       if (other == NULL) {
+                               continue;
+                       }
+                       // Only update if lighting was not completed.
+                       if (block->isLightingComplete(bank, d) &&
+                                       other->isLightingComplete(bank, 5 - d))
+                               continue;
+                       // Reset flags
+                       block->setLightingComplete(bank, d, true);
+                       other->setLightingComplete(bank, 5 - d, true);
+                       // The two blocks and their connecting surfaces
+                       MapBlock *blocks[] = {block, other};
+                       VoxelArea areas[] = {block_borders[d], block_borders[5 - d]};
+                       // For both blocks
+                       for (u8 blocknum = 0; blocknum < 2; blocknum++) {
+                               MapBlock *b = blocks[blocknum];
+                               VoxelArea a = areas[blocknum];
+                               // For all nodes
+                               for (s32 x = a.MinEdge.X; x <= a.MaxEdge.X; x++)
+                               for (s32 z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++)
+                               for (s32 y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
+                                       MapNode n = b->getNodeNoCheck(x, y, z,
+                                               &is_valid_position);
+                                       u8 light = n.getLight(bank, ndef);
+                                       // Sunlight is fixed
+                                       if (light < LIGHT_SUN) {
+                                               // Unlight if not correct
+                                               if (!is_light_locally_correct(map, ndef, bank,
+                                                               v3s16(x, y, z) + b->getPosRelative())) {
+                                                       // Initialize for unlighting
+                                                       n.setLight(bank, 0, ndef);
+                                                       b->setNodeNoCheck(x, y, z, n);
+                                                       modified_blocks[b->getPos()]=b;
+                                                       disappearing_lights.push(light,
+                                                               relative_v3(x, y, z), b->getPos(), b,
+                                                               6);
+                                               }
+                                       }
+                               }
+                       }
+               }
+               // Remove lights
+               unspread_light(map, ndef, bank, disappearing_lights, light_sources,
+                       modified_blocks);
+               // Initialize light values for light spreading.
+               for (u8 i = 0; i <= LIGHT_SUN; i++) {
+                       const std::vector<ChangingLight> &lights = light_sources.lights[i];
+                       for (std::vector<ChangingLight>::const_iterator it = lights.begin();
+                                       it < lights.end(); it++) {
+                               MapNode n = it->block->getNodeNoCheck(it->rel_position,
+                                       &is_valid_position);
+                               n.setLight(bank, i, ndef);
+                               it->block->setNodeNoCheck(it->rel_position, n);
+                       }
+               }
+               // Spread lights.
+               spread_light(map, ndef, bank, light_sources, modified_blocks);
+       }
+}
+
 VoxelLineIterator::VoxelLineIterator(
        const v3f &start_position,
        const v3f &line_vector) :
index 5eff8f7ac86329f3376704f38fd1c11067871afe..bf1638fa36f57c9f6a3aa7cb48551e10e6c980cb 100644 (file)
@@ -22,8 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "voxel.h"
 #include "mapnode.h"
-#include <set>
-#include <map>
+#include "util/container.h"
+#include "util/cpp11_container.h"
 
 class Map;
 class MapBlock;
@@ -69,10 +69,21 @@ SunlightPropagateResult propagateSunlight(VoxelManipulator &v, VoxelArea a,
  */
 void update_lighting_nodes(
        Map *map,
-       INodeDefManager *ndef,
        std::vector<std::pair<v3s16, MapNode> > &oldnodes,
        std::map<v3s16, MapBlock*> &modified_blocks);
 
+/*!
+ * Updates borders of the given mapblock.
+ * Only updates if the block was marked with incomplete
+ * lighting and the neighbor is also loaded.
+ *
+ * \param block the block to update
+ * \param modified_blocks output, contains all map blocks that
+ * the function modified
+ */
+void update_block_border_lighting(Map *map, MapBlock *block,
+       std::map<v3s16, MapBlock*> &modified_blocks);
+
 /*!
  * This class iterates trough voxels that intersect with
  * a line. The collision detection does not see nodeboxes,