/*
Minetest
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "map.h"
#include "mapsector.h"
#include "mapblock.h"
#include "filesys.h"
#include "voxel.h"
#include "porting.h"
#include "serialization.h"
#include "nodemetadata.h"
#include "settings.h"
#include "log.h"
#include "profiler.h"
#include "nodedef.h"
#include "gamedef.h"
#include "util/directiontables.h"
#include "util/mathconstants.h"
#include "rollback_interface.h"
#include "environment.h"
#include "emerge.h"
#include "mapgen_v6.h"
#include "mg_biome.h"
#include "config.h"
#include "server.h"
#include "database.h"
#include "database-dummy.h"
#include "database-sqlite3.h"
#include <deque>
#include <queue>
#if USE_LEVELDB
#include "database-leveldb.h"
#endif
#if USE_REDIS
#include "database-redis.h"
#endif
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
/*
Map
*/
Map::Map(std::ostream &dout, IGameDef *gamedef):
m_dout(dout),
m_gamedef(gamedef),
m_sector_cache(NULL),
m_transforming_liquid_loop_count_multiplier(1.0f),
m_unprocessed_count(0),
m_inc_trending_up_start_time(0),
m_queue_size_timer_started(false)
{
}
Map::~Map()
{
/*
Free all MapSectors
*/
for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
i != m_sectors.end(); ++i)
{
delete i->second;
}
}
void Map::addEventReceiver(MapEventReceiver *event_receiver)
{
m_event_receivers.insert(event_receiver);
}
void Map::removeEventReceiver(MapEventReceiver *event_receiver)
{
m_event_receivers.erase(event_receiver);
}
void Map::dispatchEvent(MapEditEvent *event)
{
for(std::set<MapEventReceiver*>::iterator
i = m_event_receivers.begin();
i != m_event_receivers.end(); ++i)
{
(*i)->onMapEditEvent(event);
}
}
MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
{
if(m_sector_cache != NULL && p == m_sector_cache_p){
MapSector * sector = m_sector_cache;
return sector;
}
std::map<v2s16, MapSector*>::iterator n = m_sectors.find(p);
if(n == m_sectors.end())
return NULL;
MapSector *sector = n->second;
// Cache the last result
m_sector_cache_p = p;
m_sector_cache = sector;
return sector;
}
MapSector * Map::getSectorNoGenerateNoEx(v2s16 p)
{
return getSectorNoGenerateNoExNoLock(p);
}
MapSector * Map::getSectorNoGenerate(v2s16 p)
{
MapSector *sector = getSectorNoGenerateNoEx(p);
if(sector == NULL)
throw InvalidPositionException();
return sector;
}
MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
{
v2s16 p2d(p3d.X, p3d.Z);
MapSector * sector = getSectorNoGenerateNoEx(p2d);
if(sector == NULL)
return NULL;
MapBlock *block = sector->getBlockNoCreateNoEx(p3d.Y);
return block;
}
MapBlock * Map::getBlockNoCreate(v3s16 p3d)
{
MapBlock *block = getBlockNoCreateNoEx(p3d);
if(block == NULL)
throw InvalidPositionException();
return block;
}
bool Map::isNodeUnderground(v3s16 p)
{
v3s16 blockpos = getNodeBlockPos(p);
try{
MapBlock * block = getBlockNoCreate(blockpos);
return block->getIsUnderground();
}
catch(InvalidPositionException &e)
{
return false;
}
}
bool Map::isValidPosition(v3s16 p)
{
v3s16 blockpos = getNodeBlockPos(p);
MapBlock *block = getBlockNoCreate(blockpos);
return (block != NULL);
}
// Returns a CONTENT_IGNORE node if not found
MapNode Map::getNodeNoEx(v3s16 p, bool *is_valid_position)
{
v3s16 blockpos = getNodeBlockPos(p);
MapBlock *block = getBlockNoCreateNoEx(blockpos);
if (block == NULL) {
if (is_valid_position != NULL)
*is_valid_position = false;
return MapNode(CONTENT_IGNORE);
}
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
bool is_valid_p;
MapNode node = block->getNodeNoCheck(relpos, &is_valid_p);
if (is_valid_position != NULL)
*is_valid_position = is_valid_p;
return node;
}
#if 0
// Deprecated
// throws InvalidPositionException if not found
// TODO: Now this is deprecated, getNodeNoEx should be renamed
MapNode Map::getNode(v3s16 p)
{
v3s16 blockpos = getNodeBlockPos(p);
MapBlock *block = getBlockNoCreateNoEx(blockpos);
if (block == NULL)
throw InvalidPositionException();
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
bool is_valid_position;
MapNode node = block->getNodeNoCheck(relpos, &is_valid_position);
if (!is_valid_position)
throw InvalidPositionException();
return node;
}
#endif
// throws InvalidPositionException if not found
void Map::setNode(v3s16 p, MapNode & n)
{
v3s16 blockpos = getNodeBlockPos(p);
MapBlock *block = getBlockNoCreate(blockpos);
v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
// Never allow placing CONTENT_IGNORE, it fucks up stuff
if(n.getContent() == CONTENT_IGNORE){
bool temp_bool;
errorstream<<"Map::setNode(): Not allowing to place CONTENT_IGNORE"
<<" while trying to replace \""
<<m_gamedef->ndef()->get(block->getNodeNoCheck(relpos, &temp_bool)).name
<<"\" at "<<PP(p)<<" (block "<<PP(blockpos)<<")"<<std::endl;
debug_stacks_print_to(infostream);
return;
}
block->setNodeNoCheck(relpos, n);
}
/*
Goes recursively through the neighbours of the node.
Alters only transparent nodes.
If the lighting of the neighbour is lower than the lighting of
the node was (before changing it to 0 at the step before), the
lighting of the neighbour is set to 0 and then the same stuff
repeats for the neighbour.
The ending nodes of the routine are stored in light_sources.
This is useful when a light is removed. In such case, this
routine can be called for the light node and then again for
light_sources to re-light the area without the removed light.
values of from_nodes are lighting values.
*/
void Map::unspreadLight(enum LightBank bank,
std::map<v3s16, u8> & from_nodes,
std::set<v3s16> & light_sources,
std::map<v3s16, MapBlock*> & modified_blocks)
{
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
};
if(from_nodes.empty())
return;
u32 blockchangecount = 0;
std::map<v3s16, u8> unlighted_nodes;
/*
Initialize block cache
*/
|