diff options
-rw-r--r-- | src/environment.cpp | 86 | ||||
-rw-r--r-- | src/environment.h | 5 | ||||
-rw-r--r-- | src/map.cpp | 198 | ||||
-rw-r--r-- | src/map.h | 4 | ||||
-rw-r--r-- | src/server.cpp | 5 | ||||
-rw-r--r-- | src/server.h | 1 | ||||
-rw-r--r-- | src/servercommand.cpp | 52 |
7 files changed, 185 insertions, 166 deletions
diff --git a/src/environment.cpp b/src/environment.cpp index 174ee1e1d..142271849 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -647,6 +647,92 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime) } } +void ServerEnvironment::clearAllObjects() +{ + infostream<<"ServerEnvironment::clearAllObjects(): " + <<"Removing all active objects"<<std::endl; + core::list<u16> objects_to_remove; + for(core::map<u16, ServerActiveObject*>::Iterator + i = m_active_objects.getIterator(); + i.atEnd()==false; i++) + { + ServerActiveObject* obj = i.getNode()->getValue(); + u16 id = i.getNode()->getKey(); + v3f objectpos = obj->getBasePosition(); + // Delete static object if block is loaded + if(obj->m_static_exists){ + MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block); + if(block){ + block->m_static_objects.remove(id); + block->raiseModified(MOD_STATE_WRITE_NEEDED); + obj->m_static_exists = false; + } + } + // If known by some client, don't delete immediately + if(obj->m_known_by_count > 0){ + obj->m_pending_deactivation = true; + obj->m_removed = true; + continue; + } + // Delete active object + delete obj; + // Id to be removed from m_active_objects + objects_to_remove.push_back(id); + } + // Remove references from m_active_objects + for(core::list<u16>::Iterator i = objects_to_remove.begin(); + i != objects_to_remove.end(); i++) + { + m_active_objects.remove(*i); + } + + core::list<v3s16> loadable_blocks; + infostream<<"ServerEnvironment::clearAllObjects(): " + <<"Listing all loadable blocks"<<std::endl; + m_map->listAllLoadableBlocks(loadable_blocks); + infostream<<"ServerEnvironment::clearAllObjects(): " + <<"Done listing all loadable blocks: " + <<loadable_blocks.size() + <<", now clearing"<<std::endl; + u32 report_interval = loadable_blocks.size() / 10; + u32 num_blocks_checked = 0; + u32 num_blocks_cleared = 0; + u32 num_objs_cleared = 0; + for(core::list<v3s16>::Iterator i = loadable_blocks.begin(); + i != loadable_blocks.end(); i++) + { + v3s16 p = *i; + MapBlock *block = m_map->emergeBlock(p, false); + if(!block){ + errorstream<<"ServerEnvironment::clearAllObjects(): " + <<"Failed to emerge block "<<PP(p)<<std::endl; + continue; + } + u32 num_stored = block->m_static_objects.m_stored.size(); + u32 num_active = block->m_static_objects.m_active.size(); + if(num_stored != 0 || num_active != 0){ + block->m_static_objects.m_stored.clear(); + block->m_static_objects.m_active.clear(); + block->raiseModified(MOD_STATE_WRITE_NEEDED); + num_objs_cleared += num_stored + num_active; + num_blocks_cleared++; + } + num_blocks_checked++; + + if(num_blocks_checked % report_interval == 0){ + float percent = 100.0 * (float)num_blocks_checked / + loadable_blocks.size(); + infostream<<"ServerEnvironment::clearAllObjects(): " + <<"Cleared "<<num_objs_cleared<<" objects" + <<" in "<<num_blocks_cleared<<" blocks (" + <<percent<<"%)"<<std::endl; + } + } + infostream<<"ServerEnvironment::clearAllObjects(): " + <<"Finished: Cleared "<<num_objs_cleared<<" objects" + <<" in "<<num_blocks_cleared<<" blocks"<<std::endl; +} + static void getMob_dungeon_master(Settings &properties) { properties.set("looks", "dungeon_master"); diff --git a/src/environment.h b/src/environment.h index d93caac3b..5d2fe5551 100644 --- a/src/environment.h +++ b/src/environment.h @@ -218,6 +218,11 @@ public: void addActiveBlockModifier(ActiveBlockModifier *abm); + /* Other stuff */ + + // Clear all objects, loading and going through every MapBlock + void clearAllObjects(); + private: /* diff --git a/src/map.cpp b/src/map.cpp index 943d9772a..c7f635feb 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -2623,152 +2623,6 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate) return NULL; } -#if 0 - /* - Do not generate over-limit - */ - if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE - || p.X > 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) - { - infostream<<"emergeBlock: createSector() failed: " - <<e.what()<<std::endl; - infostream<<"Path to failed sector: "<<getSectorDir(p2d) - <<std::endl - <<"You could try to delete it."<<std::endl; - throw e; - } - catch(VersionMismatchException &e) - { - infostream<<"emergeBlock: createSector() failed: " - <<e.what()<<std::endl; - infostream<<"Path to failed sector: "<<getSectorDir(p2d) - <<std::endl - <<"You could try to delete it."<<std::endl; - throw e; - } - - /* - Try to get a block from the sector - */ - - bool does_not_exist = false; - bool lighting_expired = false; - MapBlock *block = sector->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 - //infostream<<"emergeBlock(): Returning already valid block"<<std::endl; - return block; - } - - /* - If block was not found on disk and not going to generate a - new one, make sure there is a dummy block in place. - */ - if(only_from_disk && (does_not_exist || lighting_expired)) - { - //infostream<<"emergeBlock(): Was not on disk but not generating"<<std::endl; - - if(block == NULL) - { - // Create dummy block - block = new MapBlock(this, p, true); - - // Add block to sector - sector->insertBlock(block); - } - // Done. - return block; - } - - //infostream<<"Not found on disk, generating."<<std::endl; - // 0ms - //TimeTaker("emergeBlock() generate"); - - //infostream<<"emergeBlock(): Didn't find valid block -> making one"<<std::endl; - - /* - If the block doesn't exist, generate the block. - */ - if(does_not_exist) - { - block = generateBlock(p, block, sector, changed_blocks, - lighting_invalidated_blocks); - } - - if(lighting_expired) - { - lighting_invalidated_blocks.insert(p, block); - } - -#if 0 - /* - Initially update sunlight - */ - { - core::map<v3s16, bool> 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 @@ -2867,6 +2721,12 @@ void ServerMap::verifyDatabase() { throw FileNotGoodException("Cannot prepare write statement"); } + d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL); + if(d != SQLITE_OK) { + infostream<<"WARNING: Database list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl; + throw FileNotGoodException("Cannot prepare read statement"); + } + infostream<<"Server: Database opened"<<std::endl; } } @@ -3039,6 +2899,52 @@ void ServerMap::save(bool only_changed) } } +static s32 unsignedToSigned(s32 i, s32 max_positive) +{ + if(i < max_positive) + return i; + else + return i - 2*max_positive; +} + +// modulo of a negative number does not work consistently in C +static sqlite3_int64 pythonmodulo(sqlite3_int64 i, sqlite3_int64 mod) +{ + if(i >= 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<v3s16> &dst) +{ + if(loadFromFolders()){ + errorstream<<"Map::listAllLoadableBlocks(): Result will be missing " + <<"all blocks that are stored in flat files"<<std::endl; + } + + { + verifyDatabase(); + + while(sqlite3_step(m_database_list) == SQLITE_ROW) + { + sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0); + v3s16 p = getIntegerAsBlock(block_i); + //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl; + dst.push_back(p); + } + } +} + void ServerMap::saveMapMeta() { DSTACK(__FUNCTION_NAME); @@ -383,6 +383,7 @@ public: void verifyDatabase(); // Get an integer suitable for a block static sqlite3_int64 getBlockAsInteger(const v3s16 pos); + static v3s16 getIntegerAsBlock(sqlite3_int64 i); // Returns true if the database file does not exist bool loadFromFolders(); @@ -394,6 +395,8 @@ public: void save(bool only_changed); //void loadAll(); + void listAllLoadableBlocks(core::list<v3s16> &dst); + // Saves map seed and possibly other stuff void saveMapMeta(); void loadMapMeta(); @@ -458,6 +461,7 @@ private: sqlite3 *m_database; sqlite3_stmt *m_database_read; sqlite3_stmt *m_database_write; + sqlite3_stmt *m_database_list; }; /* diff --git a/src/server.cpp b/src/server.cpp index 14c019d52..3a3d0b823 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -4136,6 +4136,11 @@ void Server::notifyPlayer(const char *name, const std::wstring msg) SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg); } +void Server::notifyPlayers(const std::wstring msg) +{ + BroadcastChatMessage(msg); +} + v3f findSpawnPos(ServerMap &map) { //return v3f(50,50,50)*BS; diff --git a/src/server.h b/src/server.h index 1e7e41c96..dac7e2826 100644 --- a/src/server.h +++ b/src/server.h @@ -475,6 +475,7 @@ public: // Envlock and conlock should be locked when calling this void notifyPlayer(const char *name, const std::wstring msg); + void notifyPlayers(const std::wstring msg); private: diff --git a/src/servercommand.cpp b/src/servercommand.cpp index 3c0e6d510..a09003960 100644 --- a/src/servercommand.cpp +++ b/src/servercommand.cpp @@ -277,6 +277,35 @@ void cmd_banunban(std::wostringstream &os, ServerCommandContext *ctx) } } +void cmd_clearobjects(std::wostringstream &os, + ServerCommandContext *ctx) +{ + if((ctx->privs & PRIV_SERVER) ==0) + { + os<<L"-!- You don't have permission to do that"; + return; + } + + actionstream<<ctx->player->getName() + <<" clears all objects"<<std::endl; + + { + std::wstring msg; + msg += L"Clearing all objects. This may take long."; + msg += L" You may experience a timeout. (by "; + msg += narrow_to_wide(ctx->player->getName()); + msg += L")"; + ctx->server->notifyPlayers(msg); + } + + ctx->env->clearAllObjects(); + + actionstream<<"object clearing done"<<std::endl; + + os<<L"*** cleared all objects"; + ctx->flags |= SEND_TO_OTHERS; +} + std::wstring processServerCommand(ServerCommandContext *ctx) { @@ -302,45 +331,28 @@ std::wstring processServerCommand(ServerCommandContext *ctx) os<<L" ban unban"; } else if(ctx->parms[0] == L"status") - { cmd_status(os, ctx); - } else if(ctx->parms[0] == L"privs") - { cmd_privs(os, ctx); - } else if(ctx->parms[0] == L"grant" || ctx->parms[0] == L"revoke") - { cmd_grantrevoke(os, ctx); - } else if(ctx->parms[0] == L"time") - { cmd_time(os, ctx); - } else if(ctx->parms[0] == L"shutdown") - { cmd_shutdown(os, ctx); - } else if(ctx->parms[0] == L"setting") - { cmd_setting(os, ctx); - } else if(ctx->parms[0] == L"teleport") - { cmd_teleport(os, ctx); - } else if(ctx->parms[0] == L"ban" || ctx->parms[0] == L"unban") - { cmd_banunban(os, ctx); - } else if(ctx->parms[0] == L"me") - { cmd_me(os, ctx); - } + else if(ctx->parms[0] == L"clearobjects") + cmd_clearobjects(os, ctx); else - { os<<L"-!- Invalid command: " + ctx->parms[0]; - } + return os.str(); } |