}
}
+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");
void addActiveBlockModifier(ActiveBlockModifier *abm);
+ /* Other stuff */
+
+ // Clear all objects, loading and going through every MapBlock
+ void clearAllObjects();
+
private:
/*
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
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;
}
}
}
}
+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);
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();
void save(bool only_changed);
//void loadAll();
+ void listAllLoadableBlocks(core::list<v3s16> &dst);
+
// Saves map seed and possibly other stuff
void saveMapMeta();
void loadMapMeta();
sqlite3 *m_database;
sqlite3_stmt *m_database_read;
sqlite3_stmt *m_database_write;
+ sqlite3_stmt *m_database_list;
};
/*
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;
// 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:
}
}
+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)
{
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();
}