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){
+ errorstream<<"Map::setNode(): Not allowing to place CONTENT_IGNORE"
+ <<" while trying to replace \""
+ <<m_gamedef->ndef()->get(block->getNodeNoCheck(relpos)).name
+ <<"\" at "<<PP(p)<<" (block "<<PP(blockpos)<<")"<<std::endl;
+ debug_stacks_print_to(infostream);
+ return;
+ }
block->setNodeNoCheck(relpos, n);
}
for(s16 y=-1; y<=1; y++)
for(s16 x=-1; x<=1; x++)
{
- v3s16 p(x,y,z);
- MapBlock *block = getBlockNoCreateNoEx(p);
+ 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(p, p);
+ vmanip.initialEmerge(p2, p2);
}*/
// Lighting of block will be updated completely
/*
Add intial metadata
*/
-
- NodeMetadata *meta_proto = nodemgr->get(n).initial_metadata;
- if(meta_proto)
- {
- NodeMetadata *meta = meta_proto->clone(m_gamedef);
- meta->setOwner(player_name);
- setNodeMetadata(p, meta);
+
+ std::string metadata_name = nodemgr->get(n).metadata_name;
+ if(metadata_name != ""){
+ NodeMetadata *meta = NodeMetadata::create(metadata_name, m_gamedef);
+ if(!meta){
+ errorstream<<"Failed to create node metadata \""
+ <<metadata_name<<"\""<<std::endl;
+ } else {
+ meta->setOwner(player_name);
+ setNodeMetadata(p, meta);
+ }
}
/*
{
bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
+ // Profile modified reasons
+ Profiler modprofiler;
+
core::list<v2s16> sector_deletion_queue;
u32 deleted_blocks_count = 0;
u32 saved_blocks_count = 0;
+ u32 block_count_all = 0;
core::map<v2s16, MapSector*>::Iterator si;
if(block->getModified() != MOD_STATE_CLEAN
&& save_before_unloading)
{
+ modprofiler.add(block->getModifiedReason(), 1);
saveBlock(block);
saved_blocks_count++;
}
else
{
all_blocks_deleted = false;
+ block_count_all++;
}
}
<<" 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);
+ }
}
}
switch (liquid_type) {
case LIQUID_SOURCE:
liquid_level = LIQUID_LEVEL_SOURCE;
- liquid_kind = nodemgr->get(n0).liquid_alternative_flowing;
+ liquid_kind = nodemgr->getId(nodemgr->get(n0).liquid_alternative_flowing);
break;
case LIQUID_FLOWING:
liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
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 = nodemgr->get(nb.n.getContent()).liquid_alternative_flowing;
- if (nodemgr->get(nb.n.getContent()).liquid_alternative_flowing !=liquid_kind) {
+ liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
+ if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
neutrals[num_neutrals++] = nb;
} else {
- sources[num_sources++] = nb;
+ // Do not count bottom source, it will screw things up
+ if(dirs[i].Y != -1)
+ sources[num_sources++] = nb;
}
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 = nodemgr->get(nb.n.getContent()).liquid_alternative_flowing;
- if (nodemgr->get(nb.n.getContent()).liquid_alternative_flowing != liquid_kind) {
+ liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
+ if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
neutrals[num_neutrals++] = nb;
} else {
flows[num_flows++] = nb;
// 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 = nodemgr->get(liquid_kind).liquid_alternative_source;
+ new_node_content = nodemgr->getId(nodemgr->get(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;
emergeSector(v2s16(0,0));
// Initially write whole map
- save(false);
+ save(MOD_STATE_CLEAN);
}
ServerMap::~ServerMap()
if(m_map_saving_enabled)
{
// Save only changed parts
- save(true);
+ save(MOD_STATE_WRITE_AT_UNLOAD);
infostream<<"Server: saved map to "<<m_savedir<<std::endl;
}
else
data->no_op = false;
data->seed = m_seed;
data->blockpos = blockpos;
- data->nodemgr = m_gamedef->ndef();
+ data->nodedef = m_gamedef->ndef();
/*
Create the whole area of this and the neighboring blocks
/*infostream<<"Resulting vmanip:"<<std::endl;
data->vmanip.print(infostream);*/
-
+
+ // Make sure affected blocks are loaded
+ for(s16 x=-1; x<=1; x++)
+ for(s16 z=-1; z<=1; z++)
+ for(s16 y=-1; y<=1; y++)
+ {
+ v3s16 p(blockpos.X+x, blockpos.Y+y, blockpos.Z+z);
+ // Load from disk if not already in memory
+ emergeBlock(p, false);
+ }
+
/*
Blit generated stuff to map
NOTE: blitBackAll adds nearly everything to changed_blocks
/*
Set block as modified
*/
- block->raiseModified(MOD_STATE_WRITE_NEEDED);
+ block->raiseModified(MOD_STATE_WRITE_NEEDED,
+ "finishBlockMake updateDayNightDiff");
}
/*
Save changed parts of map
NOTE: Will be saved later.
*/
- //save(true);
+ //save(MOD_STATE_WRITE_AT_UNLOAD);
/*infostream<<"finishBlockMake() done for ("<<blockpos.X<<","<<blockpos.Y<<","
<<blockpos.Z<<")"<<std::endl;*/
return cc;
}
-void ServerMap::save(bool only_changed)
+void ServerMap::save(ModifiedState save_level)
{
DSTACK(__FUNCTION_NAME);
if(m_map_saving_enabled == false)
return;
}
- if(only_changed == false)
+ if(save_level == MOD_STATE_CLEAN)
infostream<<"ServerMap: Saving whole map, this can take time."
<<std::endl;
- if(only_changed == false || m_map_metadata_changed)
+ if(m_map_metadata_changed || save_level == MOD_STATE_CLEAN)
{
saveMapMeta();
}
+ // Profile modified reasons
+ Profiler modprofiler;
+
u32 sector_meta_count = 0;
u32 block_count = 0;
u32 block_count_all = 0; // Number of blocks in memory
- beginSave();
+ // Don't do anything with sqlite unless something is really saved
+ bool save_started = false;
+
core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
for(; i.atEnd() == false; i++)
{
ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
assert(sector->getId() == MAPSECTOR_SERVER);
- if(sector->differs_from_disk || only_changed == false)
+ if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN)
{
saveSectorMeta(sector);
sector_meta_count++;
sector->getBlocks(blocks);
core::list<MapBlock*>::Iterator j;
- //sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL);
for(j=blocks.begin(); j!=blocks.end(); j++)
{
MapBlock *block = *j;
block_count_all++;
- if(block->getModified() >= MOD_STATE_WRITE_NEEDED
- || only_changed == false)
+ if(block->getModified() >= save_level)
{
+ // Lazy beginSave()
+ if(!save_started){
+ beginSave();
+ save_started = true;
+ }
+
+ modprofiler.add(block->getModifiedReason(), 1);
+
saveBlock(block);
block_count++;
<<block->getPos().Z<<")"
<<std::endl;*/
}
- //sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL);
}
}
- endSave();
+ if(save_started)
+ endSave();
/*
Only print if something happened or saved whole map
*/
- if(only_changed == false || sector_meta_count != 0
+ if(save_level == MOD_STATE_CLEAN || sector_meta_count != 0
|| block_count != 0)
{
infostream<<"ServerMap: Written: "
<<block_count<<" block files"
<<", "<<block_count_all<<" blocks in memory."
<<std::endl;
+ PrintInfo(infostream); // ServerMap/ClientMap:
+ infostream<<"Blocks modified by: "<<std::endl;
+ modprofiler.print(infostream);
}
}