X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmap.cpp;h=ba4130ca29e860a9b6196cc66a1be5ecdb990988;hb=9b907dd65a2c045d10605894fdaea504200e2be7;hp=4204c2a02ee88b055e018284188c5b6e96c7bb85;hpb=570a8dbf22e8e33fed22292941edfaa38d41c289;p=minetest.git diff --git a/src/map.cpp b/src/map.cpp index 4204c2a02..ba4130ca2 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -28,13 +28,31 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "porting.h" #include "mapgen.h" #include "nodemetadata.h" +#include "content_mapnode.h" +#ifndef SERVER +#include +#endif +#include "settings.h" +#include "log.h" +#include "profiler.h" + +#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" -extern "C" { - #include "sqlite3.h" -} /* SQLite format specification: - Initially only replaces sectors/ and sectors2/ + + If map.sqlite does not exist in the save dir + or the block was not found in the database + the map will try to load from sectors folder. + In either case, map.sqlite will be created + and all future saves will save there. + + Structure of map.sqlite: + Tables: + blocks + (PK) INT pos + BLOB data */ /* @@ -332,7 +350,7 @@ void Map::unspreadLight(enum LightBank bank, */ /*if(light_sources.find(n2pos)) { - std::cout<<"Removed from light_sources"<getKey(); //v3s16 pos = *j; - //dstream<<"pos=("<get("")) { core::map::Iterator i; i = blocks_to_update.getIterator(); @@ -785,7 +803,7 @@ void Map::updateLighting(enum LightBank bank, { u32 diff = modified_blocks.size() - count_was; count_was = modified_blocks.size(); - dstream<<"unspreadLight modified "<clone(); + meta->setOwner(player_name); setNodeMetadata(p, meta); } @@ -1281,7 +1300,8 @@ bool Map::addNodeWithEvent(v3s16 p, MapNode n) bool succeeded = true; try{ core::map modified_blocks; - addNodeAndUpdate(p, n, modified_blocks); + std::string st = std::string(""); + addNodeAndUpdate(p, n, modified_blocks, st); // Copy modified_blocks to event for(core::map::Iterator @@ -1399,6 +1419,7 @@ void Map::timerUpdate(float dtime, float unload_timeout, core::map::Iterator si; + beginSave(); si = m_sectors.getIterator(); for(; si.atEnd() == false; si++) { @@ -1408,6 +1429,7 @@ void Map::timerUpdate(float dtime, float unload_timeout, core::list blocks; sector->getBlocks(blocks); + for(core::list::Iterator i = blocks.begin(); i != blocks.end(); i++) { @@ -1446,18 +1468,19 @@ void Map::timerUpdate(float dtime, float unload_timeout, sector_deletion_queue.push_back(si.getNode()->getKey()); } } + endSave(); // Finally delete the empty sectors deleteSectors(sector_deletion_queue); if(deleted_blocks_count != 0) { - PrintInfo(dstream); // ServerMap/ClientMap: - dstream<<"Unloaded "< & modified_blocks) u32 initial_size = m_transforming_liquid.size(); /*if(initial_size != 0) - dstream<<"transformLiquids(): initial_size="<get("fixed_map_seed").empty()) { m_seed = (((u64)(myrand()%0xffff)<<0) + ((u64)(myrand()%0xffff)<<16) @@ -1888,7 +1924,7 @@ ServerMap::ServerMap(std::string savedir): } else { - m_seed = g_settings.getU64("fixed_map_seed"); + m_seed = g_settings->getU64("fixed_map_seed"); } /* @@ -1913,7 +1949,7 @@ ServerMap::ServerMap(std::string savedir): // If directory is empty, it is safe to save into it. if(fs::GetDirListing(m_savedir).size() == 0) { - dstream<getBool("enable_mapgen_debug_info"); if(enable_mapgen_debug_info) - dstream<<"initBlockMake(): ("< &changed_blocks) { v3s16 blockpos = data->blockpos; - /*dstream<<"finishBlockMake(): ("<no_op) { - //dstream<<"finishBlockMake(): no-op"<getBool("enable_mapgen_debug_info"); - /*dstream<<"Resulting vmanip:"<vmanip.print(dstream);*/ + /*infostream<<"Resulting vmanip:"<vmanip.print(infostream);*/ /* Blit generated stuff to map @@ -2127,7 +2173,7 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data, } if(enable_mapgen_debug_info) - dstream<<"finishBlockMake: changed_blocks.size()=" + infostream<<"finishBlockMake: changed_blocks.size()=" <getBool("enable_mapgen_debug_info"); TimeTaker timer("generateBlock"); @@ -2379,7 +2426,7 @@ MapBlock * ServerMap::generateBlock( */ if(blockpos_over_limit(p)) { - dstream<<__FUNCTION_NAME<<": Block position over limit"<getNode(p); if(n.getContent() == CONTENT_IGNORE) { - dstream<<"CONTENT_IGNORE at " + infostream<<"CONTENT_IGNORE at " <<"("< MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE) - throw InvalidPositionException("emergeBlock(): pos. over limit"); - - v2s16 p2d(p.X, p.Z); - s16 block_y = p.Y; - /* - This will create or load a sector if not found in memory. - If block exists on disk, it will be loaded. - */ - ServerMapSector *sector; - try{ - sector = createSector(p2d); - //sector = emergeSector(p2d, changed_blocks); - } - catch(InvalidPositionException &e) - { - dstream<<"emergeBlock: createSector() failed: " - <getBlockNoCreateNoEx(block_y); - - // If not found, try loading from disk - if(block == NULL) - { - block = loadBlock(p); - } - - // Handle result - if(block == NULL) - { - does_not_exist = true; - } - else if(block->isDummy() == true) - { - does_not_exist = true; - } - else if(block->getLightingExpired()) - { - lighting_expired = true; - } - else - { - // Valid block - //dstream<<"emergeBlock(): Returning already valid block"<insertBlock(block); - } - // Done. - return block; - } - - //dstream<<"Not found on disk, generating."< making one"< light_sources; - bool black_air_left = false; - bool bottom_invalid = - block->propagateSunlight(light_sources, true, - &black_air_left); - - // If sunlight didn't reach everywhere and part of block is - // above ground, lighting has to be properly updated - //if(black_air_left && some_part_underground) - if(black_air_left) - { - lighting_invalidated_blocks[block->getPos()] = block; - } - - if(bottom_invalid) - { - lighting_invalidated_blocks[block->getPos()] = block; - } - } -#endif - - return block; -} -#endif - s16 ServerMap::findGroundLevel(v2s16 p2d) { #if 0 @@ -2766,6 +2667,81 @@ s16 ServerMap::findGroundLevel(v2s16 p2d) //return (s16)level; } +void ServerMap::createDatabase() { + int e; + assert(m_database); + e = sqlite3_exec(m_database, + "CREATE TABLE IF NOT EXISTS `blocks` (" + "`pos` INT NOT NULL PRIMARY KEY," + "`data` BLOB" + ");" + , NULL, NULL, NULL); + if(e == SQLITE_ABORT) + throw FileNotGoodException("Could not create database structure"); + else + infostream<<"Server: Database structure was created"; +} + +void ServerMap::verifyDatabase() { + if(m_database) + return; + + { + std::string dbp = m_savedir + DIR_DELIM + "map.sqlite"; + bool needs_create = false; + int d; + + /* + Open the database connection + */ + + createDirs(m_savedir); + + if(!fs::PathExists(dbp)) + needs_create = true; + + d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL); + if(d != SQLITE_OK) { + infostream<<"WARNING: Database failed to open: "<::Iterator i = m_sectors.getIterator(); for(; i.atEnd() == false; i++) { @@ -2883,6 +2860,8 @@ void ServerMap::save(bool only_changed) core::list blocks; sector->getBlocks(blocks); core::list::Iterator j; + + //sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL); for(j=blocks.begin(); j!=blocks.end(); j++) { MapBlock *block = *j; @@ -2895,14 +2874,16 @@ void ServerMap::save(bool only_changed) saveBlock(block); block_count++; - /*dstream<<"ServerMap: Written block (" + /*infostream<<"ServerMap: Written block (" <getPos().X<<"," <getPos().Y<<"," <getPos().Z<<")" <= 0) + return i % mod; + return mod - ((-i) % mod); +} + +v3s16 ServerMap::getIntegerAsBlock(sqlite3_int64 i) +{ + s32 x = unsignedToSigned(pythonmodulo(i, 4096), 2048); + i = (i - x) / 4096; + s32 y = unsignedToSigned(pythonmodulo(i, 4096), 2048); + i = (i - y) / 4096; + s32 z = unsignedToSigned(pythonmodulo(i, 4096), 2048); + return v3s16(x,y,z); +} + +void ServerMap::listAllLoadableBlocks(core::list &dst) +{ + if(loadFromFolders()){ + errorstream<<"Map::listAllLoadableBlocks(): Result will be missing " + <<"all blocks that are stored in flat files"<isDummy()) { /*v3s16 p = block->getPos(); - dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block " + infostream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block " <<"("<getPos(); + +#if 0 v2s16 p2d(p3d.X, p3d.Z); std::string sectordir = getSectorDir(p2d); createDirs(sectordir); - std::string fullpath = sectordir+"/"+getBlockFilename(p3d); + std::string fullpath = sectordir+DIR_DELIM+getBlockFilename(p3d); std::ofstream o(fullpath.c_str(), std::ios_base::binary); if(o.good() == false) throw FileNotGoodException("Cannot open block data"); - +#endif /* [0] u8 serialization version [1] data */ + + verifyDatabase(); + + std::ostringstream o(std::ios_base::binary); + o.write((char*)&version, 1); // Write basic data @@ -3201,7 +3245,23 @@ void ServerMap::saveBlock(MapBlock *block) // Write extra data stored on disk block->serializeDiskExtra(o, version); - + + // Write block to database + + std::string tmp = o.str(); + const char *bytes = tmp.c_str(); + + if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK) + infostream<<"WARNING: Block position failed to bind: "<resetModified(); } @@ -3210,7 +3270,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto { DSTACK(__FUNCTION_NAME); - std::string fullpath = sectordir+"/"+blockfile; + std::string fullpath = sectordir+DIR_DELIM+blockfile; try{ std::ifstream is(fullpath.c_str(), std::ios_base::binary); @@ -3262,6 +3322,9 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto if(version < SER_FMT_VER_HIGHEST || save_after_load) { saveBlock(block); + + // Should be in database now, so delete the old file + fs::RecursiveDelete(fullpath); } // We just loaded it from the disk, so it's up-to-date. @@ -3270,7 +3333,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto } catch(SerializationError &e) { - dstream<<"WARNING: Invalid block data on disk " + infostream<<"WARNING: Invalid block data on disk " <<"fullpath="< data(block_size); + is.read((char*)*data, block_size);*/ + + // This will always return a sector because we're the server + //MapSector *sector = emergeSector(p2d); + + MapBlock *block = NULL; + bool created_new = false; + block = sector->getBlockNoCreateNoEx(p3d.Y); + if(block == NULL) + { + block = sector->createBlankBlockNoInsert(p3d.Y); + created_new = true; + } + + // Read basic data + block->deSerialize(is, version); + + // Read extra data stored on disk + block->deSerializeDiskExtra(is, version); + + // If it's a new block, insert it to the map + if(created_new) + sector->insertBlock(block); + + /* + Save blocks loaded in old format in new format + */ + + if(version < SER_FMT_VER_HIGHEST || save_after_load) + { + saveBlock(block); + } + + // We just loaded it from, so it's up-to-date. + block->resetModified(); + + } + catch(SerializationError &e) + { + infostream<<"WARNING: Invalid block data in database " + <<" (SerializationError). " + <<"what()="<::Iterator si; @@ -3523,7 +3700,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) int time2 = time(0); if(time2 > time1 + 4) { - dstream<<"ClientMap::renderMap(): " + infostream<<"ClientMap::renderMap(): " "Rendering takes ages, returning." <getPos(), camera_position, - camera_direction, range, &d) == false) + camera_direction, camera_fov, + range, &d) == false) { continue; } @@ -3580,6 +3758,8 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) /*if(m_control.range_all == false && d - 0.5*BS*MAP_BLOCKSIZE > range) continue;*/ + + blocks_in_range++; #if 1 /* @@ -3598,8 +3778,10 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) // Mesh has not been expired and there is no mesh: // block has no content - if(block->mesh == NULL && mesh_expired == false) + if(block->mesh == NULL && mesh_expired == false){ + blocks_in_range_without_mesh++; continue; + } } f32 faraway = BS*50; @@ -3637,9 +3819,11 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) JMutexAutoLock lock(block->mesh_mutex); scene::SMesh *mesh = block->mesh; - - if(mesh == NULL) + + if(mesh == NULL){ + blocks_in_range_without_mesh++; continue; + } blocks_would_have_drawn++; if(blocks_drawn >= m_control.wanted_max_blocks @@ -3651,7 +3835,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) sector_blocks_drawn++; u32 c = mesh->getMeshBufferCount(); - + bool stuff_actually_drawn = false; for(u32 i=0; igetMeshBuffer(i); @@ -3662,16 +3846,25 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) // Render transparent on transparent pass and likewise. if(transparent == is_transparent_pass) { + if(buf->getVertexCount() == 0) + errorstream<<"Block ["<setMaterial(buf->getMaterial()); driver->drawMeshBuffer(buf); vertex_count += buf->getVertexCount(); + meshbuffer_count++; + stuff_actually_drawn = true; } } + if(stuff_actually_drawn) + blocks_had_pass_meshbuf++; + else + blocks_without_stuff++; } } // foreach sectorblocks @@ -3681,13 +3874,66 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) } } + std::string prefix = "CM: "; + + // Log only on solid pass because values are the same + if(pass == scene::ESNRP_SOLID){ + g_profiler->avg(prefix+"blocks in range", blocks_in_range); + if(blocks_in_range != 0) + g_profiler->avg(prefix+"blocks in range without mesh (frac)", + (float)blocks_in_range_without_mesh/blocks_in_range); + g_profiler->avg(prefix+"blocks drawn", blocks_drawn); + } + + if(pass == scene::ESNRP_SOLID) + prefix = "CM: solid: "; + else + prefix = "CM: transparent: "; + + g_profiler->avg(prefix+"vertices drawn", vertex_count); + if(blocks_had_pass_meshbuf != 0) + g_profiler->avg(prefix+"meshbuffers per block", + (float)meshbuffer_count / (float)blocks_had_pass_meshbuf); + if(blocks_drawn != 0) + g_profiler->avg(prefix+"empty blocks (frac)", + (float)blocks_without_stuff / blocks_drawn); + m_control.blocks_drawn = blocks_drawn; m_control.blocks_would_have_drawn = blocks_would_have_drawn; - /*dstream<<"renderMap(): is_transparent_pass="<getBool("free_move") == false) + { + post_effect_color = video::SColor(255, 0, 0, 0); + } + if (post_effect_color.getAlpha() != 0) + { + // Draw a full-screen rectangle + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + v2u32 ss = driver->getScreenSize(); + core::rect rect(0,0, ss.X, ss.Y); + driver->draw2DRectangle(post_effect_color, rect); + } +} + bool ClientMap::setTempMod(v3s16 p, NodeMod mod, core::map *affected_blocks) { @@ -3905,7 +4151,7 @@ MapVoxelManipulator::MapVoxelManipulator(Map *map) MapVoxelManipulator::~MapVoxelManipulator() { - /*dstream<<"MapVoxelManipulator: blocks: "<getBlockNoCreate(p); if(block->isDummy()) @@ -3969,7 +4215,7 @@ void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id) m_loaded_blocks.insert(p, !block_data_inexistent); } - //dstream<<"emerge done"<getBlockNoCreateNoEx(p); if(block == NULL) { - dstream<<"WARNING: "<<__FUNCTION_NAME + infostream<<"WARNING: "<<__FUNCTION_NAME <<": got NULL block " <<"("<