Add '/clearobjects quick'
authorKahrl <kahrl@gmx.net>
Mon, 8 Feb 2016 21:20:04 +0000 (22:20 +0100)
committerparamat <mat.gregory@virginmedia.com>
Thu, 11 Feb 2016 04:22:58 +0000 (04:22 +0000)
builtin/game/chatcommands.lua
doc/lua_api.txt
src/environment.cpp
src/environment.h
src/script/lua_api/l_env.cpp
src/script/lua_api/l_env.h

index fff893b282de1b149e0d6304eb643cb6ac9084a5..9557a27c4179f949766180ec00be0b3aafcddad5 100644 (file)
@@ -848,14 +848,24 @@ core.register_chatcommand("kick", {
 })
 
 core.register_chatcommand("clearobjects", {
+       params = "[full|quick]",
        description = "clear all objects in world",
        privs = {server=true},
        func = function(name, param)
+               options = {}
+               if param == "" or param == "full" then
+                       options.mode = "full"
+               elseif param == "quick" then
+                       options.mode = "quick"
+               else
+                       return false, "Invalid usage, see /help clearobjects."
+               end
+
                core.log("action", name .. " clears all objects.")
                core.chat_send_all("Clearing all objects.  This may take long."
                                .. "  You may experience a timeout.  (by "
                                .. name .. ")")
-               core.clear_objects()
+               core.clear_objects(options)
                core.log("action", "Object clearing done.")
                core.chat_send_all("*** Cleared all objects.")
        end,
index b6bc957c16a76574a8c904c924850091f4a21d5f..5f4e0642345641d1c568a59fdbf07eb50d454d67 100644 (file)
@@ -2046,8 +2046,12 @@ and `minetest.auth_reload` call the authetification handler.
 * `minetest.generate_decorations(vm, pos1, pos2)`
     * Generate all registered decorations within the VoxelManip `vm` and in the area from `pos1` to `pos2`.
     * `pos1` and `pos2` are optional and default to mapchunk minp and maxp.
-* `minetest.clear_objects()`
-    * clear all objects in the environments
+* `minetest.clear_objects([options])`
+    * Clear all objects in the environment
+    * Takes an optional table as an argument with the field `mode`.
+        * mode = `"full"`: Load and go through every mapblock, clearing objects (default).
+        * mode = `"quick"`: Clear objects immediately in loaded mapblocks;
+          clear objects in unloaded mapblocks only when the mapblocks are next activated.
 * `minetest.emerge_area(pos1, pos2, [callback], [param])`
     * Queue all blocks in the area from `pos1` to `pos2`, inclusive, to be asynchronously
     * fetched from memory, loaded from disk, or if inexistent, generates them.
index 38316cb3141d84c8a2a23aafcf2a298dc42094ad..3bf5e1f0a41b6fd8803a10d231b8017a93ca18e4 100644 (file)
@@ -354,6 +354,7 @@ ServerEnvironment::ServerEnvironment(ServerMap *map,
        m_active_block_interval_overload_skip(0),
        m_game_time(0),
        m_game_time_fraction_counter(0),
+       m_last_clear_objects_time(0),
        m_recommended_send_interval(0.1),
        m_max_lag_estimate(0.1)
 {
@@ -503,6 +504,7 @@ void ServerEnvironment::saveMeta()
        Settings args;
        args.setU64("game_time", m_game_time);
        args.setU64("time_of_day", getTimeOfDay());
+       args.setU64("last_clear_objects_time", m_last_clear_objects_time);
        args.writeLines(ss);
        ss<<"EnvArgsEnd\n";
 
@@ -546,6 +548,13 @@ void ServerEnvironment::loadMeta()
                // This is not as important
                setTimeOfDay(9000);
        }
+
+       try {
+               m_last_clear_objects_time = args.getU64("last_clear_objects_time");
+       } catch (SettingNotFoundException &e) {
+               // If missing, do as if clearObjects was never called
+               m_last_clear_objects_time = 0;
+       }
 }
 
 struct ActiveABM
@@ -739,13 +748,19 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
        // Get time difference
        u32 dtime_s = 0;
        u32 stamp = block->getTimestamp();
-       if(m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
-               dtime_s = m_game_time - block->getTimestamp();
+       if (m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED)
+               dtime_s = m_game_time - stamp;
        dtime_s += additional_dtime;
 
        /*infostream<<"ServerEnvironment::activateBlock(): block timestamp: "
                        <<stamp<<", game time: "<<m_game_time<<std::endl;*/
 
+       // Remove stored static objects if clearObjects was called since block's timestamp
+       if (stamp == BLOCK_TIMESTAMP_UNDEFINED || stamp < m_last_clear_objects_time) {
+               block->m_static_objects.m_stored.clear();
+               // do not set changed flag to avoid unnecessary mapblock writes
+       }
+
        // Set current time as timestamp
        block->setTimestampNoChangedFlag(m_game_time);
 
@@ -858,22 +873,22 @@ void ServerEnvironment::getObjectsInsideRadius(std::vector<u16> &objects, v3f po
        }
 }
 
-void ServerEnvironment::clearAllObjects()
+void ServerEnvironment::clearObjects(ClearObjectsMode mode)
 {
-       infostream<<"ServerEnvironment::clearAllObjects(): "
-                       <<"Removing all active objects"<<std::endl;
+       infostream << "ServerEnvironment::clearObjects(): "
+               << "Removing all active objects" << std::endl;
        std::vector<u16> objects_to_remove;
-       for(std::map<u16, ServerActiveObject*>::iterator
+       for (std::map<u16, ServerActiveObject*>::iterator
                        i = m_active_objects.begin();
                        i != m_active_objects.end(); ++i) {
                ServerActiveObject* obj = i->second;
-               if(obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
+               if (obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
                        continue;
                u16 id = i->first;
                // Delete static object if block is loaded
-               if(obj->m_static_exists){
+               if (obj->m_static_exists) {
                        MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
-                       if(block){
+                       if (block) {
                                block->m_static_objects.remove(id);
                                block->raiseModified(MOD_STATE_WRITE_NEEDED,
                                                MOD_REASON_CLEAR_ALL_OBJECTS);
@@ -881,7 +896,7 @@ void ServerEnvironment::clearAllObjects()
                        }
                }
                // If known by some client, don't delete immediately
-               if(obj->m_known_by_count > 0){
+               if (obj->m_known_by_count > 0) {
                        obj->m_pending_deactivation = true;
                        obj->m_removed = true;
                        continue;
@@ -893,39 +908,46 @@ void ServerEnvironment::clearAllObjects()
                m_script->removeObjectReference(obj);
 
                // Delete active object
-               if(obj->environmentDeletes())
+               if (obj->environmentDeletes())
                        delete obj;
                // Id to be removed from m_active_objects
                objects_to_remove.push_back(id);
        }
 
        // Remove references from m_active_objects
-       for(std::vector<u16>::iterator i = objects_to_remove.begin();
+       for (std::vector<u16>::iterator i = objects_to_remove.begin();
                        i != objects_to_remove.end(); ++i) {
                m_active_objects.erase(*i);
        }
 
        // Get list of loaded blocks
        std::vector<v3s16> loaded_blocks;
-       infostream<<"ServerEnvironment::clearAllObjects(): "
-                       <<"Listing all loaded blocks"<<std::endl;
+       infostream << "ServerEnvironment::clearObjects(): "
+               << "Listing all loaded blocks" << std::endl;
        m_map->listAllLoadedBlocks(loaded_blocks);
-       infostream<<"ServerEnvironment::clearAllObjects(): "
-                       <<"Done listing all loaded blocks: "
-                       <<loaded_blocks.size()<<std::endl;
+       infostream << "ServerEnvironment::clearObjects(): "
+               << "Done listing all loaded blocks: "
+               << loaded_blocks.size()<<std::endl;
 
        // Get list of loadable blocks
        std::vector<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;
+       if (mode == CLEAR_OBJECTS_MODE_FULL) {
+               infostream << "ServerEnvironment::clearObjects(): "
+                       << "Listing all loadable blocks" << std::endl;
+               m_map->listAllLoadableBlocks(loadable_blocks);
+               infostream << "ServerEnvironment::clearObjects(): "
+                       << "Done listing all loadable blocks: "
+                       << loadable_blocks.size() << std::endl;
+       } else {
+               loadable_blocks = loaded_blocks;
+       }
+
+       infostream << "ServerEnvironment::clearObjects(): "
+               << "Now clearing objects in " << loadable_blocks.size()
+               << " blocks" << std::endl;
 
        // Grab a reference on each loaded block to avoid unloading it
-       for(std::vector<v3s16>::iterator i = loaded_blocks.begin();
+       for (std::vector<v3s16>::iterator i = loaded_blocks.begin();
                        i != loaded_blocks.end(); ++i) {
                v3s16 p = *i;
                MapBlock *block = m_map->getBlockNoCreateNoEx(p);
@@ -934,24 +956,27 @@ void ServerEnvironment::clearAllObjects()
        }
 
        // Remove objects in all loadable blocks
-       u32 unload_interval = g_settings->getS32("max_clearobjects_extra_loaded_blocks");
-       unload_interval = MYMAX(unload_interval, 1);
+       u32 unload_interval = U32_MAX;
+       if (mode == CLEAR_OBJECTS_MODE_FULL) {
+               unload_interval = g_settings->getS32("max_clearobjects_extra_loaded_blocks");
+               unload_interval = MYMAX(unload_interval, 1);
+       }
        u32 report_interval = loadable_blocks.size() / 10;
        u32 num_blocks_checked = 0;
        u32 num_blocks_cleared = 0;
        u32 num_objs_cleared = 0;
-       for(std::vector<v3s16>::iterator i = loadable_blocks.begin();
+       for (std::vector<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;
+               if (!block) {
+                       errorstream << "ServerEnvironment::clearObjects(): "
+                               << "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){
+               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,
@@ -961,23 +986,23 @@ void ServerEnvironment::clearAllObjects()
                }
                num_blocks_checked++;
 
-               if(report_interval != 0 &&
-                               num_blocks_checked % report_interval == 0){
+               if (report_interval != 0 &&
+                               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;
+                               loadable_blocks.size();
+                       infostream << "ServerEnvironment::clearObjects(): "
+                               << "Cleared " << num_objs_cleared << " objects"
+                               << " in " << num_blocks_cleared << " blocks ("
+                               << percent << "%)" << std::endl;
                }
-               if(num_blocks_checked % unload_interval == 0){
+               if (num_blocks_checked % unload_interval == 0) {
                        m_map->unloadUnreferencedBlocks();
                }
        }
        m_map->unloadUnreferencedBlocks();
 
        // Drop references that were added above
-       for(std::vector<v3s16>::iterator i = loaded_blocks.begin();
+       for (std::vector<v3s16>::iterator i = loaded_blocks.begin();
                        i != loaded_blocks.end(); ++i) {
                v3s16 p = *i;
                MapBlock *block = m_map->getBlockNoCreateNoEx(p);
@@ -985,9 +1010,11 @@ void ServerEnvironment::clearAllObjects()
                block->refDrop();
        }
 
-       infostream<<"ServerEnvironment::clearAllObjects(): "
-                       <<"Finished: Cleared "<<num_objs_cleared<<" objects"
-                       <<" in "<<num_blocks_cleared<<" blocks"<<std::endl;
+       m_last_clear_objects_time = m_game_time;
+
+       infostream << "ServerEnvironment::clearObjects(): "
+               << "Finished: Cleared " << num_objs_cleared << " objects"
+               << " in " << num_blocks_cleared << " blocks" << std::endl;
 }
 
 void ServerEnvironment::step(float dtime)
index 1aaa5091fc5bf6fbb5210b6791df5aa88791ef4d..e7b818dc998815c80cc182db7376b15e590543d0 100644 (file)
@@ -203,6 +203,18 @@ public:
 private:
 };
 
+/*
+       Operation mode for ServerEnvironment::clearObjects()
+*/
+enum ClearObjectsMode {
+       // Load and go through every mapblock, clearing objects
+       CLEAR_OBJECTS_MODE_FULL,
+
+       // Clear objects immediately in loaded mapblocks;
+       // clear objects in unloaded mapblocks only when the mapblocks are next activated.
+       CLEAR_OBJECTS_MODE_QUICK,
+};
+
 /*
        The server-side environment.
 
@@ -319,8 +331,8 @@ public:
        // Find all active objects inside a radius around a point
        void getObjectsInsideRadius(std::vector<u16> &objects, v3f pos, float radius);
 
-       // Clear all objects, loading and going through every MapBlock
-       void clearAllObjects();
+       // Clear objects, loading and going through every MapBlock
+       void clearObjects(ClearObjectsMode mode);
 
        // This makes stuff happen
        void step(f32 dtime);
@@ -410,6 +422,10 @@ private:
        u32 m_game_time;
        // A helper variable for incrementing the latter
        float m_game_time_fraction_counter;
+       // Time of last clearObjects call (game time).
+       // When a mapblock older than this is loaded, its objects are cleared.
+       u32 m_last_clear_objects_time;
+       // Active block modifiers
        std::vector<ABMWithState> m_abms;
        // An interval for generally sending object positions and stuff
        float m_recommended_send_interval;
index 084b1b4408fd8655bfa586e55f523f86fbf2575b..b445b1eb9ac9f10810d6ab1f49f4fbc228bdb41c 100644 (file)
@@ -36,6 +36,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "emerge.h"
 #include "pathfinder.h"
 
+struct EnumString ModApiEnvMod::es_ClearObjectsMode[] =
+{
+       {CLEAR_OBJECTS_MODE_FULL,  "full"},
+       {CLEAR_OBJECTS_MODE_QUICK, "quick"},
+       {0, NULL},
+};
+
 ///////////////////////////////////////////////////////////////////////////////
 
 
@@ -727,13 +734,20 @@ int ModApiEnvMod::l_get_voxel_manip(lua_State *L)
        return 1;
 }
 
-// clear_objects()
+// clear_objects([options])
 // clear all objects in the environment
+// where options = {mode = "full" or "quick"}
 int ModApiEnvMod::l_clear_objects(lua_State *L)
 {
        GET_ENV_PTR;
 
-       env->clearAllObjects();
+       ClearObjectsMode mode = CLEAR_OBJECTS_MODE_FULL;
+       if (lua_istable(L, 1)) {
+               mode = (ClearObjectsMode)getenumfield(L, 1, "mode",
+                       ModApiEnvMod::es_ClearObjectsMode, mode);
+       }
+
+       env->clearObjects(mode);
        return 0;
 }
 
index 424556d4b238ed63f7b8ae52bd90b2e3a6e434a4..4f8dfcd3cbc8d77508d694040a3284fb26dca11e 100644 (file)
@@ -170,6 +170,8 @@ private:
 
 public:
        static void Initialize(lua_State *L, int top);
+
+       static struct EnumString es_ClearObjectsMode[];
 };
 
 class LuaABM : public ActiveBlockModifier {