Add /clearobjects

This commit is contained in:
Perttu Ahola 2011-10-18 00:01:50 +03:00
parent ea1fda5ebc
commit 78f4142f4f
7 changed files with 185 additions and 166 deletions

@ -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");

@ -218,6 +218,11 @@ public:
void addActiveBlockModifier(ActiveBlockModifier *abm);
/* Other stuff */
// Clear all objects, loading and going through every MapBlock
void clearAllObjects();
private:
/*

@ -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;
};
/*

@ -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;

@ -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:

@ -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();
}