aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKahrl <kahrl@gmx.net>2016-02-08 22:20:04 +0100
committerparamat <mat.gregory@virginmedia.com>2016-02-11 04:22:58 +0000
commitb1428ab4bb1e2cf73bc8ac951d41d22203ea68a0 (patch)
tree6cc3abacb6afef178ead78405277ae161e31c7dd
parent47464c9344a1a4817ad6e4c6ec44526df305b1f6 (diff)
downloadminetest-b1428ab4bb1e2cf73bc8ac951d41d22203ea68a0.tar.gz
minetest-b1428ab4bb1e2cf73bc8ac951d41d22203ea68a0.tar.bz2
minetest-b1428ab4bb1e2cf73bc8ac951d41d22203ea68a0.zip
Add '/clearobjects quick'
-rw-r--r--builtin/game/chatcommands.lua12
-rw-r--r--doc/lua_api.txt8
-rw-r--r--src/environment.cpp115
-rw-r--r--src/environment.h20
-rw-r--r--src/script/lua_api/l_env.cpp18
-rw-r--r--src/script/lua_api/l_env.h2
6 files changed, 124 insertions, 51 deletions
diff --git a/builtin/game/chatcommands.lua b/builtin/game/chatcommands.lua
index fff893b28..9557a27c4 100644
--- a/builtin/game/chatcommands.lua
+++ b/builtin/game/chatcommands.lua
@@ -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,
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index b6bc957c1..5f4e06423 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -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.
diff --git a/src/environment.cpp b/src/environment.cpp
index 38316cb31..3bf5e1f0a 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -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)
diff --git a/src/environment.h b/src/environment.h
index 1aaa5091f..e7b818dc9 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -204,6 +204,18 @@ 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.
This is not thread-safe. Server uses an environment mutex.
@@ -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;
diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp
index 084b1b440..b445b1eb9 100644
--- a/src/script/lua_api/l_env.cpp
+++ b/src/script/lua_api/l_env.cpp
@@ -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;
}
diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h
index 424556d4b..4f8dfcd3c 100644
--- a/src/script/lua_api/l_env.h
+++ b/src/script/lua_api/l_env.h
@@ -170,6 +170,8 @@ private:
public:
static void Initialize(lua_State *L, int top);
+
+ static struct EnumString es_ClearObjectsMode[];
};
class LuaABM : public ActiveBlockModifier {