mirror of
https://github.com/minetest/minetest.git
synced 2024-09-12 00:26:50 +02:00
Add /clearobjects
This commit is contained in:
parent
ea1fda5ebc
commit
78f4142f4f
@ -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:
|
||||
|
||||
/*
|
||||
|
198
src/map.cpp
198
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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user