-/*
- A single-node source variation of the above.
-*/
-void Map::lightNeighbors(enum LightBank bank,
- v3s16 pos,
- std::map<v3s16, MapBlock*> & modified_blocks)
-{
- std::set<v3s16> from_nodes;
- from_nodes.insert(pos);
- spreadLight(bank, from_nodes, modified_blocks);
-}
-
-v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
-{
- INodeDefManager *nodemgr = m_gamedef->ndef();
-
- 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
- };
-
- u8 brightest_light = 0;
- v3s16 brightest_pos(0,0,0);
- bool found_something = false;
-
- // Loop through 6 neighbors
- for(u16 i=0; i<6; i++){
- // Get the position of the neighbor node
- v3s16 n2pos = p + dirs[i];
- MapNode n2;
- try{
- n2 = getNode(n2pos);
- }
- catch(InvalidPositionException &e)
- {
- continue;
- }
- if(n2.getLight(bank, nodemgr) > brightest_light || found_something == false){
- brightest_light = n2.getLight(bank, nodemgr);
- brightest_pos = n2pos;
- found_something = true;
- }
- }
-
- if(found_something == false)
- throw InvalidPositionException();
-
- return brightest_pos;
-}
-
-/*
- Propagates sunlight down from a node.
- Starting point gets sunlight.
-
- Returns the lowest y value of where the sunlight went.
-
- Mud is turned into grass in where the sunlight stops.
-*/
-s16 Map::propagateSunlight(v3s16 start,
- std::map<v3s16, MapBlock*> & modified_blocks)
-{
- INodeDefManager *nodemgr = m_gamedef->ndef();
-
- s16 y = start.Y;
- for(; ; y--)
- {
- v3s16 pos(start.X, y, start.Z);
-
- v3s16 blockpos = getNodeBlockPos(pos);
- MapBlock *block;
- try{
- block = getBlockNoCreate(blockpos);
- }
- catch(InvalidPositionException &e)
- {
- break;
- }
-
- v3s16 relpos = pos - blockpos*MAP_BLOCKSIZE;
- MapNode n = block->getNode(relpos);
-
- if(nodemgr->get(n).sunlight_propagates)
- {
- n.setLight(LIGHTBANK_DAY, LIGHT_SUN, nodemgr);
- block->setNode(relpos, n);
-
- modified_blocks[blockpos] = block;
- }
- else
- {
- // Sunlight goes no further
- break;
- }
- }
- return y + 1;
-}
-
-void Map::updateLighting(enum LightBank bank,
- std::map<v3s16, MapBlock*> & a_blocks,
- std::map<v3s16, MapBlock*> & modified_blocks)
-{
- INodeDefManager *nodemgr = m_gamedef->ndef();
-
- /*m_dout<<DTIME<<"Map::updateLighting(): "
- <<a_blocks.size()<<" blocks."<<std::endl;*/
-
- //TimeTaker timer("updateLighting");
-
- // For debugging
- //bool debug=true;
- //u32 count_was = modified_blocks.size();
-
- std::map<v3s16, MapBlock*> blocks_to_update;
-
- std::set<v3s16> light_sources;
-
- std::map<v3s16, u8> unlight_from;
-
- int num_bottom_invalid = 0;
-
- {
- //TimeTaker t("first stuff");
-
- for(std::map<v3s16, MapBlock*>::iterator i = a_blocks.begin();
- i != a_blocks.end(); ++i)
- {
- MapBlock *block = i->second;
-
- for(;;)
- {
- // Don't bother with dummy blocks.
- if(block->isDummy())
- break;
-
- v3s16 pos = block->getPos();
- v3s16 posnodes = block->getPosRelative();
- modified_blocks[pos] = block;
- blocks_to_update[pos] = block;
-
- /*
- Clear all light from block
- */
- for(s16 z=0; z<MAP_BLOCKSIZE; z++)
- for(s16 x=0; x<MAP_BLOCKSIZE; x++)
- for(s16 y=0; y<MAP_BLOCKSIZE; y++)
- {
-
- try{
- v3s16 p(x,y,z);
- MapNode n = block->getNode(p);
- u8 oldlight = n.getLight(bank, nodemgr);
- n.setLight(bank, 0, nodemgr);
- block->setNode(p, n);
-
- // If node sources light, add to list
- u8 source = nodemgr->get(n).light_source;
- if(source != 0)
- light_sources.insert(p + posnodes);
-
- // Collect borders for unlighting
- if((x==0 || x == MAP_BLOCKSIZE-1
- || y==0 || y == MAP_BLOCKSIZE-1
- || z==0 || z == MAP_BLOCKSIZE-1)
- && oldlight != 0)
- {
- v3s16 p_map = p + posnodes;
- unlight_from[p_map] = oldlight;
- }
- }
- catch(InvalidPositionException &e)
- {
- /*
- This would happen when dealing with a
- dummy block.
- */
- //assert(0);
- infostream<<"updateLighting(): InvalidPositionException"
- <<std::endl;
- }
- }
-
- if(bank == LIGHTBANK_DAY)
- {
- bool bottom_valid = block->propagateSunlight(light_sources);
-
- if(!bottom_valid)
- num_bottom_invalid++;
-
- // If bottom is valid, we're done.
- if(bottom_valid)
- break;
- }
- else if(bank == LIGHTBANK_NIGHT)
- {
- // For night lighting, sunlight is not propagated
- break;
- }
- else
- {
- // Invalid lighting bank
- assert(0);
- }
-
- /*infostream<<"Bottom for sunlight-propagated block ("
- <<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid"
- <<std::endl;*/
-
- // Bottom sunlight is not valid; get the block and loop to it
-
- pos.Y--;
- try{
- block = getBlockNoCreate(pos);
- }
- catch(InvalidPositionException &e)
- {
- assert(0);
- }
-
- }
- }
-
- }
-
- /*
- Enable this to disable proper lighting for speeding up map
- generation for testing or whatever
- */
-#if 0
- //if(g_settings->get(""))
- {
- core::map<v3s16, MapBlock*>::Iterator i;
- i = blocks_to_update.getIterator();
- for(; i.atEnd() == false; i++)
- {
- MapBlock *block = i.getNode()->getValue();
- v3s16 p = block->getPos();
- block->setLightingExpired(false);
- }
- return;
- }
-#endif
-
-#if 1
- {
- //TimeTaker timer("unspreadLight");
- unspreadLight(bank, unlight_from, light_sources, modified_blocks);
- }
-
- /*if(debug)
- {
- u32 diff = modified_blocks.size() - count_was;
- count_was = modified_blocks.size();
- infostream<<"unspreadLight modified "<<diff<<std::endl;
- }*/
-
- {
- //TimeTaker timer("spreadLight");
- spreadLight(bank, light_sources, modified_blocks);
- }
-
- /*if(debug)
- {
- u32 diff = modified_blocks.size() - count_was;
- count_was = modified_blocks.size();
- infostream<<"spreadLight modified "<<diff<<std::endl;
- }*/
-#endif
-
-#if 0
- {
- //MapVoxelManipulator vmanip(this);
-
- // Make a manual voxel manipulator and load all the blocks
- // that touch the requested blocks
- ManualMapVoxelManipulator vmanip(this);
-
- {
- //TimeTaker timer("initialEmerge");
-
- core::map<v3s16, MapBlock*>::Iterator i;
- i = blocks_to_update.getIterator();
- for(; i.atEnd() == false; i++)
- {
- MapBlock *block = i.getNode()->getValue();
- v3s16 p = block->getPos();
-
- // Add all surrounding blocks
- vmanip.initialEmerge(p - v3s16(1,1,1), p + v3s16(1,1,1));
-
- /*
- Add all surrounding blocks that have up-to-date lighting
- NOTE: This doesn't quite do the job (not everything
- appropriate is lighted)
- */
- /*for(s16 z=-1; z<=1; z++)
- for(s16 y=-1; y<=1; y++)
- for(s16 x=-1; x<=1; x++)
- {
- v3s16 p2 = p + v3s16(x,y,z);
- MapBlock *block = getBlockNoCreateNoEx(p2);
- if(block == NULL)
- continue;
- if(block->isDummy())
- continue;
- if(block->getLightingExpired())
- continue;
- vmanip.initialEmerge(p2, p2);
- }*/
-
- // Lighting of block will be updated completely
- block->setLightingExpired(false);
- }
- }
-
- {
- //TimeTaker timer("unSpreadLight");
- vmanip.unspreadLight(bank, unlight_from, light_sources, nodemgr);
- }
- {
- //TimeTaker timer("spreadLight");
- vmanip.spreadLight(bank, light_sources, nodemgr);
- }
- {
- //TimeTaker timer("blitBack");
- vmanip.blitBack(modified_blocks);
- }
- /*infostream<<"emerge_time="<<emerge_time<<std::endl;
- emerge_time = 0;*/
- }
-#endif
-
- //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
-}
-
-void Map::updateLighting(std::map<v3s16, MapBlock*> & a_blocks,
- std::map<v3s16, MapBlock*> & modified_blocks)
-{
- updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
- updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
-
- /*
- Update information about whether day and night light differ
- */
- for(std::map<v3s16, MapBlock*>::iterator
- i = modified_blocks.begin();
- i != modified_blocks.end(); ++i)
- {
- MapBlock *block = i->second;
- block->expireDayNightDiff();
- }
-}
-
-/*
-*/
-void Map::addNodeAndUpdate(v3s16 p, MapNode n,
- std::map<v3s16, MapBlock*> &modified_blocks,
- bool remove_metadata)
-{
- INodeDefManager *ndef = m_gamedef->ndef();
-
- /*PrintInfo(m_dout);
- m_dout<<DTIME<<"Map::addNodeAndUpdate(): p=("
- <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
-
- /*
- From this node to nodes underneath:
- If lighting is sunlight (1.0), unlight neighbours and
- set lighting to 0.
- Else discontinue.
- */
-
- v3s16 toppos = p + v3s16(0,1,0);
- //v3s16 bottompos = p + v3s16(0,-1,0);
-
- bool node_under_sunlight = true;
- std::set<v3s16> light_sources;
-
- /*
- Collect old node for rollback
- */
- RollbackNode rollback_oldnode(this, p, m_gamedef);
-
- /*
- If there is a node at top and it doesn't have sunlight,
- there has not been any sunlight going down.
-
- Otherwise there probably is.
- */
- try{
- MapNode topnode = getNode(toppos);
-
- if(topnode.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN)
- node_under_sunlight = false;
- }
- catch(InvalidPositionException &e)
- {
- }
-
- /*
- Remove all light that has come out of this node
- */
-
- enum LightBank banks[] =
- {
- LIGHTBANK_DAY,
- LIGHTBANK_NIGHT
- };
- for(s32 i=0; i<2; i++)
- {
- enum LightBank bank = banks[i];
-
- u8 lightwas = getNode(p).getLight(bank, ndef);
-
- // Add the block of the added node to modified_blocks
- v3s16 blockpos = getNodeBlockPos(p);
- MapBlock * block = getBlockNoCreate(blockpos);
- assert(block != NULL);
- modified_blocks[blockpos] = block;
-
- assert(isValidPosition(p));
-
- // Unlight neighbours of node.
- // This means setting light of all consequent dimmer nodes
- // to 0.
- // This also collects the nodes at the border which will spread
- // light again into this.
- unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks);
-
- n.setLight(bank, 0, ndef);
- }
-
- /*
- If node lets sunlight through and is under sunlight, it has
- sunlight too.
- */
- if(node_under_sunlight && ndef->get(n).sunlight_propagates)
- {
- n.setLight(LIGHTBANK_DAY, LIGHT_SUN, ndef);
- }
-
- /*
- Remove node metadata
- */
- if (remove_metadata) {
- removeNodeMetadata(p);
- }
-
- /*
- Set the node on the map
- */
-
- setNode(p, n);
-
- /*
- If node is under sunlight and doesn't let sunlight through,
- take all sunlighted nodes under it and clear light from them
- and from where the light has been spread.
- TODO: This could be optimized by mass-unlighting instead
- of looping
- */
- if(node_under_sunlight && !ndef->get(n).sunlight_propagates)
- {
- s16 y = p.Y - 1;
- for(;; y--){
- //m_dout<<DTIME<<"y="<<y<<std::endl;
- v3s16 n2pos(p.X, y, p.Z);
-
- MapNode n2;
- try{
- n2 = getNode(n2pos);
- }
- catch(InvalidPositionException &e)
- {
- break;
- }
-
- if(n2.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN)
- {
- unLightNeighbors(LIGHTBANK_DAY,
- n2pos, n2.getLight(LIGHTBANK_DAY, ndef),
- light_sources, modified_blocks);
- n2.setLight(LIGHTBANK_DAY, 0, ndef);
- setNode(n2pos, n2);
- }
- else
- break;
- }
- }
-
- for(s32 i=0; i<2; i++)
- {
- enum LightBank bank = banks[i];
-
- /*
- Spread light from all nodes that might be capable of doing so
- */
- spreadLight(bank, light_sources, modified_blocks);
- }
-
- /*
- Update information about whether day and night light differ
- */
- for(std::map<v3s16, MapBlock*>::iterator
- i = modified_blocks.begin();
- i != modified_blocks.end(); ++i)
- {
- i->second->expireDayNightDiff();
- }
-
- /*
- Report for rollback
- */
- if(m_gamedef->rollback())
- {
- RollbackNode rollback_newnode(this, p, m_gamedef);
- RollbackAction action;
- action.setSetNode(p, rollback_oldnode, rollback_newnode);
- m_gamedef->rollback()->reportAction(action);
- }
-
- /*
- Add neighboring liquid nodes and the node itself if it is
- liquid (=water node was added) to transform queue.
- note: todo: for liquid_finite enough to add only self node
- */
- 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(ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR)
- {
- m_transforming_liquid.push_back(p2);
- }
-
- }catch(InvalidPositionException &e)
- {
- }
- }
-}
-
-/*
-*/
-void Map::removeNodeAndUpdate(v3s16 p,
- std::map<v3s16, MapBlock*> &modified_blocks)
-{
- INodeDefManager *ndef = m_gamedef->ndef();
-
- /*PrintInfo(m_dout);
- m_dout<<DTIME<<"Map::removeNodeAndUpdate(): p=("
- <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
-
- bool node_under_sunlight = true;
-
- v3s16 toppos = p + v3s16(0,1,0);
-
- // Node will be replaced with this
- content_t replace_material = CONTENT_AIR;
-
- /*
- Collect old node for rollback
- */
- RollbackNode rollback_oldnode(this, p, m_gamedef);
-
- /*
- If there is a node at top and it doesn't have sunlight,
- there will be no sunlight going down.
- */
- try{
- MapNode topnode = getNode(toppos);
-
- if(topnode.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN)
- node_under_sunlight = false;
- }
- catch(InvalidPositionException &e)
- {
- }
-
- std::set<v3s16> light_sources;
-
- enum LightBank banks[] =
- {
- LIGHTBANK_DAY,
- LIGHTBANK_NIGHT
- };
- for(s32 i=0; i<2; i++)
- {
- enum LightBank bank = banks[i];
-
- /*
- Unlight neighbors (in case the node is a light source)
- */
- unLightNeighbors(bank, p,
- getNode(p).getLight(bank, ndef),
- light_sources, modified_blocks);
- }
-
- /*
- Remove node metadata
- */
-
- removeNodeMetadata(p);
-
- /*
- Remove the node.
- This also clears the lighting.
- */
-
- MapNode n;
- n.setContent(replace_material);
- setNode(p, n);
-
- for(s32 i=0; i<2; i++)
- {
- enum LightBank bank = banks[i];
-
- /*
- Recalculate lighting
- */
- spreadLight(bank, light_sources, modified_blocks);
- }
-
- // Add the block of the removed node to modified_blocks
- v3s16 blockpos = getNodeBlockPos(p);
- MapBlock * block = getBlockNoCreate(blockpos);
- assert(block != NULL);
- modified_blocks[blockpos] = block;
-
- /*
- If the removed node was under sunlight, propagate the
- sunlight down from it and then light all neighbors
- of the propagated blocks.
- */
- if(node_under_sunlight)
- {
- s16 ybottom = propagateSunlight(p, modified_blocks);
- /*m_dout<<DTIME<<"Node was under sunlight. "
- "Propagating sunlight";
- m_dout<<DTIME<<" -> ybottom="<<ybottom<<std::endl;*/
- s16 y = p.Y;
- for(; y >= ybottom; y--)
- {
- v3s16 p2(p.X, y, p.Z);
- /*m_dout<<DTIME<<"lighting neighbors of node ("
- <<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
- <<std::endl;*/
- lightNeighbors(LIGHTBANK_DAY, p2, modified_blocks);
- }
- }
- else
- {
- // Set the lighting of this node to 0
- // TODO: Is this needed? Lighting is cleared up there already.
- try{
- MapNode n = getNode(p);
- n.setLight(LIGHTBANK_DAY, 0, ndef);
- setNode(p, n);
- }
- catch(InvalidPositionException &e)
- {
- assert(0);
- }
- }
-
- for(s32 i=0; i<2; i++)
- {
- enum LightBank bank = banks[i];
-
- // Get the brightest neighbour node and propagate light from it
- v3s16 n2p = getBrightestNeighbour(bank, p);
- try{
- //MapNode n2 = getNode(n2p);
- lightNeighbors(bank, n2p, modified_blocks);
- }
- catch(InvalidPositionException &e)
- {
- }
- }
-
- /*
- Update information about whether day and night light differ
- */
- for(std::map<v3s16, MapBlock*>::iterator
- i = modified_blocks.begin();
- i != modified_blocks.end(); ++i)
- {
- i->second->expireDayNightDiff();
- }
-
- /*
- Report for rollback
- */
- if(m_gamedef->rollback())
- {
- RollbackNode rollback_newnode(this, p, m_gamedef);
- RollbackAction action;
- action.setSetNode(p, rollback_oldnode, rollback_newnode);
- m_gamedef->rollback()->reportAction(action);
- }
-
- /*
- Add neighboring liquid nodes and this node to transform queue.
- (it's vital for the node itself to get updated last.)
- note: todo: for liquid_finite enough to add only self node
- */
- 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<7; i++)
- {
- try
- {
-
- v3s16 p2 = p + dirs[i];
-
- MapNode n2 = getNode(p2);
- if(ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR)
- {
- m_transforming_liquid.push_back(p2);
- }
-
- }catch(InvalidPositionException &e)
- {
- }
- }
-}
-
-bool Map::addNodeWithEvent(v3s16 p, MapNode n, bool remove_metadata)
-{
- MapEditEvent event;
- event.type = remove_metadata ? MEET_ADDNODE : MEET_SWAPNODE;
- event.p = p;
- event.n = n;
-
- bool succeeded = true;
- try{
- std::map<v3s16, MapBlock*> modified_blocks;
- addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
-
- // Copy modified_blocks to event
- for(std::map<v3s16, MapBlock*>::iterator
- i = modified_blocks.begin();
- i != modified_blocks.end(); ++i)
- {
- event.modified_blocks.insert(i->first);
- }
- }
- catch(InvalidPositionException &e){
- succeeded = false;
- }
-
- dispatchEvent(&event);
-
- return succeeded;
-}
-
-bool Map::removeNodeWithEvent(v3s16 p)
-{
- MapEditEvent event;
- event.type = MEET_REMOVENODE;
- event.p = p;
-
- bool succeeded = true;
- try{
- std::map<v3s16, MapBlock*> modified_blocks;
- removeNodeAndUpdate(p, modified_blocks);
-
- // Copy modified_blocks to event
- for(std::map<v3s16, MapBlock*>::iterator
- i = modified_blocks.begin();
- i != modified_blocks.end(); ++i)
- {
- event.modified_blocks.insert(i->first);
- }
- }
- catch(InvalidPositionException &e){
- succeeded = false;
- }
-
- dispatchEvent(&event);
-
- return succeeded;
-}
-
-bool Map::getDayNightDiff(v3s16 blockpos)
-{
- try{
- v3s16 p = blockpos + v3s16(0,0,0);
- MapBlock *b = getBlockNoCreate(p);
- if(b->getDayNightDiff())
- return true;
- }
- catch(InvalidPositionException &e){}
- // Leading edges
- try{
- v3s16 p = blockpos + v3s16(-1,0,0);
- MapBlock *b = getBlockNoCreate(p);
- if(b->getDayNightDiff())
- return true;
- }
- catch(InvalidPositionException &e){}
- try{
- v3s16 p = blockpos + v3s16(0,-1,0);
- MapBlock *b = getBlockNoCreate(p);
- if(b->getDayNightDiff())
- return true;
- }
- catch(InvalidPositionException &e){}
- try{
- v3s16 p = blockpos + v3s16(0,0,-1);
- MapBlock *b = getBlockNoCreate(p);
- if(b->getDayNightDiff())
- return true;
- }
- catch(InvalidPositionException &e){}
- // Trailing edges
- try{
- v3s16 p = blockpos + v3s16(1,0,0);
- MapBlock *b = getBlockNoCreate(p);
- if(b->getDayNightDiff())
- return true;
- }
- catch(InvalidPositionException &e){}
- try{
- v3s16 p = blockpos + v3s16(0,1,0);
- MapBlock *b = getBlockNoCreate(p);
- if(b->getDayNightDiff())
- return true;
- }
- catch(InvalidPositionException &e){}
- try{
- v3s16 p = blockpos + v3s16(0,0,1);
- MapBlock *b = getBlockNoCreate(p);
- if(b->getDayNightDiff())
- return true;
- }
- catch(InvalidPositionException &e){}
-
- return false;
-}
-
-/*
- Updates usage timers
-*/
-void Map::timerUpdate(float dtime, float unload_timeout,
- std::list<v3s16> *unloaded_blocks)
-{
- bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
-
- // Profile modified reasons
- Profiler modprofiler;
-
- std::list<v2s16> sector_deletion_queue;
- u32 deleted_blocks_count = 0;
- u32 saved_blocks_count = 0;
- u32 block_count_all = 0;
-
- beginSave();
- for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
- si != m_sectors.end(); ++si)
- {
- MapSector *sector = si->second;
-
- bool all_blocks_deleted = true;
-
- std::list<MapBlock*> blocks;
- sector->getBlocks(blocks);
-
- for(std::list<MapBlock*>::iterator i = blocks.begin();
- i != blocks.end(); ++i)
- {
- MapBlock *block = (*i);
-
- block->incrementUsageTimer(dtime);
-
- if(block->refGet() == 0 && block->getUsageTimer() > unload_timeout)
- {
- v3s16 p = block->getPos();
-
- // Save if modified
- if(block->getModified() != MOD_STATE_CLEAN
- && save_before_unloading)
- {
- modprofiler.add(block->getModifiedReason(), 1);
- saveBlock(block);
- saved_blocks_count++;
- }
-
- // Delete from memory
- sector->deleteBlock(block);
-
- if(unloaded_blocks)
- unloaded_blocks->push_back(p);
-
- deleted_blocks_count++;
- }
- else
- {
- all_blocks_deleted = false;
- block_count_all++;
- }
- }
-
- if(all_blocks_deleted)
- {
- sector_deletion_queue.push_back(si->first);
- }
- }
- endSave();
-
- // Finally delete the empty sectors
- deleteSectors(sector_deletion_queue);
-
- if(deleted_blocks_count != 0)
- {
- PrintInfo(infostream); // ServerMap/ClientMap:
- infostream<<"Unloaded "<<deleted_blocks_count
- <<" blocks from memory";
- if(save_before_unloading)
- infostream<<", of which "<<saved_blocks_count<<" were written";
- infostream<<", "<<block_count_all<<" blocks in memory";
- infostream<<"."<<std::endl;
- if(saved_blocks_count != 0){
- PrintInfo(infostream); // ServerMap/ClientMap:
- infostream<<"Blocks modified by: "<<std::endl;
- modprofiler.print(infostream);
- }
- }
-}
-
-void Map::unloadUnreferencedBlocks(std::list<v3s16> *unloaded_blocks)
-{
- timerUpdate(0.0, -1.0, unloaded_blocks);
-}
-
-void Map::deleteSectors(std::list<v2s16> &list)
-{
- for(std::list<v2s16>::iterator j = list.begin();
- j != list.end(); ++j)
- {
- MapSector *sector = m_sectors[*j];
- // If sector is in sector cache, remove it from there
- if(m_sector_cache == sector)
- m_sector_cache = NULL;
- // Remove from map and delete
- m_sectors.erase(*j);
- delete sector;
- }
-}
-
-#if 0
-void Map::unloadUnusedData(float timeout,
- core::list<v3s16> *deleted_blocks)
-{
- core::list<v2s16> sector_deletion_queue;
- u32 deleted_blocks_count = 0;
- u32 saved_blocks_count = 0;
-
- core::map<v2s16, MapSector*>::Iterator si = m_sectors.getIterator();
- for(; si.atEnd() == false; si++)
- {
- MapSector *sector = si.getNode()->getValue();
-
- bool all_blocks_deleted = true;
-
- core::list<MapBlock*> blocks;
- sector->getBlocks(blocks);
- for(core::list<MapBlock*>::Iterator i = blocks.begin();
- i != blocks.end(); i++)
- {
- MapBlock *block = (*i);
-
- if(block->getUsageTimer() > timeout)
- {
- // Save if modified
- if(block->getModified() != MOD_STATE_CLEAN)
- {
- saveBlock(block);
- saved_blocks_count++;
- }
- // Delete from memory
- sector->deleteBlock(block);
- deleted_blocks_count++;
- }
- else
- {
- all_blocks_deleted = false;
- }
- }
-
- if(all_blocks_deleted)
- {
- sector_deletion_queue.push_back(si.getNode()->getKey());
- }
- }
-
- deleteSectors(sector_deletion_queue);
-
- infostream<<"Map: Unloaded "<<deleted_blocks_count<<" blocks from memory"
- <<", of which "<<saved_blocks_count<<" were wr."
- <<std::endl;
-
- //return sector_deletion_queue.getSize();
- //return deleted_blocks_count;
-}
-#endif
-
-void Map::PrintInfo(std::ostream &out)
-{
- out<<"Map: ";
-}
-
-#define WATER_DROP_BOOST 4
-
-enum NeighborType {
- NEIGHBOR_UPPER,
- NEIGHBOR_SAME_LEVEL,
- NEIGHBOR_LOWER
-};
-struct NodeNeighbor {
- MapNode n;
- NeighborType t;
- v3s16 p;
- bool l; //can liquid
- bool i; //infinity
-};
-
-void Map::transforming_liquid_add(v3s16 p) {
- m_transforming_liquid.push_back(p);
-}
-
-s32 Map::transforming_liquid_size() {
- return m_transforming_liquid.size();
-}
-
-const v3s16 g_7dirs[7] =
-{
- // +right, +top, +back
- v3s16( 0,-1, 0), // bottom
- v3s16( 0, 0, 0), // self
- v3s16( 0, 0, 1), // back
- v3s16( 0, 0,-1), // front
- v3s16( 1, 0, 0), // right
- v3s16(-1, 0, 0), // left
- v3s16( 0, 1, 0) // top
-};
-
-#define D_BOTTOM 0
-#define D_TOP 6
-#define D_SELF 1
-
-void Map::transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks)
-{
- INodeDefManager *nodemgr = m_gamedef->ndef();
-
- DSTACK(__FUNCTION_NAME);
- //TimeTaker timer("transformLiquids()");
-
- u32 loopcount = 0;
- u32 initial_size = m_transforming_liquid.size();
-
- u8 relax = g_settings->getS16("liquid_relax");
- bool fast_flood = g_settings->getS16("liquid_fast_flood");
- int water_level = g_settings->getS16("water_level");
-
- // list of nodes that due to viscosity have not reached their max level height
- UniqueQueue<v3s16> must_reflow, must_reflow_second;
-
- // List of MapBlocks that will require a lighting update (due to lava)
- std::map<v3s16, MapBlock*> lighting_modified_blocks;
-
- u16 loop_max = g_settings->getU16("liquid_loop_max");
-
- //if (m_transforming_liquid.size() > 0) errorstream << "Liquid queue size="<<m_transforming_liquid.size()<<std::endl;
-
- while (m_transforming_liquid.size() > 0)
- {
- // This should be done here so that it is done when continue is used
- if (loopcount >= initial_size || loopcount >= loop_max)
- break;
- loopcount++;
- /*
- Get a queued transforming liquid node
- */
- v3s16 p0 = m_transforming_liquid.pop_front();
- u16 total_level = 0;
- // surrounding flowing liquid nodes
- NodeNeighbor neighbors[7];
- // current level of every block
- s8 liquid_levels[7] = {-1, -1, -1, -1, -1, -1, -1};
- // target levels
- s8 liquid_levels_want[7] = {-1, -1, -1, -1, -1, -1, -1};
- s8 can_liquid_same_level = 0;
- content_t liquid_kind = CONTENT_IGNORE;
- content_t liquid_kind_flowing = CONTENT_IGNORE;
- /*
- Collect information about the environment
- */
- const v3s16 *dirs = g_7dirs;
- for (u16 i = 0; i < 7; i++) {
- NeighborType nt = NEIGHBOR_SAME_LEVEL;
- switch (i) {
- case D_TOP:
- nt = NEIGHBOR_UPPER;
- break;
- case D_BOTTOM:
- nt = NEIGHBOR_LOWER;
- break;
- }
- v3s16 npos = p0 + dirs[i];
-
- neighbors[i].n = getNodeNoEx(npos);
- neighbors[i].t = nt;
- neighbors[i].p = npos;
- neighbors[i].l = 0;
- neighbors[i].i = 0;
- NodeNeighbor & nb = neighbors[i];
-
- switch (nodemgr->get(nb.n.getContent()).liquid_type) {
- case LIQUID_NONE:
- if (nb.n.getContent() == CONTENT_AIR) {
- liquid_levels[i] = 0;
- nb.l = 1;
- }
- break;
- case LIQUID_SOURCE:
- // if this node is not (yet) of a liquid type,
- // choose the first liquid type we encounter
- if (liquid_kind_flowing == CONTENT_IGNORE)
- liquid_kind_flowing = nodemgr->getId(
- nodemgr->get(nb.n).liquid_alternative_flowing);
- if (liquid_kind == CONTENT_IGNORE)
- liquid_kind = nb.n.getContent();
- if (nb.n.getContent() == liquid_kind) {
- liquid_levels[i] = nb.n.getLevel(nodemgr); //LIQUID_LEVEL_SOURCE;
- nb.l = 1;
- nb.i = (nb.n.param2 & LIQUID_INFINITY_MASK);
- }
- break;
- case LIQUID_FLOWING:
- // if this node is not (yet) of a liquid type,
- // choose the first liquid type we encounter
- if (liquid_kind_flowing == CONTENT_IGNORE)
- liquid_kind_flowing = nb.n.getContent();
- if (liquid_kind == CONTENT_IGNORE)
- liquid_kind = nodemgr->getId(
- nodemgr->get(nb.n).liquid_alternative_source);
- if (nb.n.getContent() == liquid_kind_flowing) {
- liquid_levels[i] = nb.n.getLevel(nodemgr); //(nb.n.param2 & LIQUID_LEVEL_MASK);
- nb.l = 1;
- }
- break;
- }
-
- if (nb.l && nb.t == NEIGHBOR_SAME_LEVEL)
- ++can_liquid_same_level;
- if (liquid_levels[i] > 0)
- total_level += liquid_levels[i];
-
- /*
- infostream << "get node i=" <<(int)i<<" " << PP(npos) << " c="
- << nb.n.getContent() <<" p0="<< (int)nb.n.param0 <<" p1="
- << (int)nb.n.param1 <<" p2="<< (int)nb.n.param2 << " lt="
- << nodemgr->get(nb.n.getContent()).liquid_type
- //<< " lk=" << liquid_kind << " lkf=" << liquid_kind_flowing
- << " l="<< nb.l << " inf="<< nb.i << " nlevel=" << (int)liquid_levels[i]
- << " tlevel=" << (int)total_level << " cansame="
- << (int)can_liquid_same_level << std::endl;
- */
- }
-
- if (liquid_kind == CONTENT_IGNORE ||
- !neighbors[D_SELF].l ||
- total_level <= 0)
- continue;
-
- // fill bottom block
- if (neighbors[D_BOTTOM].l) {
- liquid_levels_want[D_BOTTOM] = total_level > LIQUID_LEVEL_SOURCE ?
- LIQUID_LEVEL_SOURCE : total_level;
- total_level -= liquid_levels_want[D_BOTTOM];
- }
-
- //relax up
- if (relax && ((p0.Y == water_level) || (fast_flood && p0.Y <= water_level)) && liquid_levels[D_TOP] == 0 &&
- liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE &&
- total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level-
- (can_liquid_same_level - relax) &&
- can_liquid_same_level >= relax + 1) {
- total_level = LIQUID_LEVEL_SOURCE * can_liquid_same_level;
- }
-
- // prevent lakes in air above unloaded blocks
- if (liquid_levels[D_TOP] == 0 && (p0.Y > water_level) && neighbors[D_BOTTOM].n.getContent() == CONTENT_IGNORE && !(loopcount % 3)) {
- --total_level;
- }
-
- // calculate self level 5 blocks
- u8 want_level =
- total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level
- ? LIQUID_LEVEL_SOURCE
- : total_level / can_liquid_same_level;
- total_level -= want_level * can_liquid_same_level;
-
- //relax down
- if (relax && p0.Y == water_level + 1 && liquid_levels[D_TOP] == 0 &&
- liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE && want_level == 0 &&
- total_level <= (can_liquid_same_level - relax) &&
- can_liquid_same_level >= relax + 1) {
- total_level = 0;
- }
-
- for (u16 ii = D_SELF; ii < D_TOP; ++ii) { // fill only same level
- if (!neighbors[ii].l)
- continue;
- liquid_levels_want[ii] = want_level;
- if (liquid_levels_want[ii] < LIQUID_LEVEL_SOURCE && total_level > 0) {
- if (loopcount % 3 || liquid_levels[ii] <= 0){
- if (liquid_levels[ii] > liquid_levels_want[ii]) {
- ++liquid_levels_want[ii];
- --total_level;
- }
- } else if (neighbors[ii].l > 0){
- ++liquid_levels_want[ii];
- --total_level;
- }
- }
- }
-
- for (u16 ii = 0; ii < 7; ++ii) {
- if (total_level < 1) break;
- if (liquid_levels_want[ii] >= 0 &&
- liquid_levels_want[ii] < LIQUID_LEVEL_SOURCE) {
- ++liquid_levels_want[ii];
- --total_level;