From 7ae51382c8a31a6d263ebb913c90025eaf90780c Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 11 Aug 2024 13:34:03 +0200 Subject: [PATCH] Refactor ABM/LBM related code --- src/script/cpp_api/s_env.cpp | 260 ++++++++++++++++++++++++++++------- src/script/cpp_api/s_env.h | 14 ++ src/script/lua_api/l_env.cpp | 87 ------------ src/script/lua_api/l_env.h | 79 +---------- src/serverenvironment.cpp | 92 ++++++------- src/serverenvironment.h | 26 ++-- src/util/basic_macros.h | 6 + 7 files changed, 295 insertions(+), 269 deletions(-) diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp index 3cbb13cd2..5068e4f4d 100644 --- a/src/script/cpp_api/s_env.cpp +++ b/src/script/cpp_api/s_env.cpp @@ -25,8 +25,102 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapgen/mapgen.h" #include "lua_api/l_env.h" #include "server.h" +#include "scripting_server.h" #include "script/common/c_content.h" +/* + LuaABM & LuaLBM +*/ + +class LuaABM : public ActiveBlockModifier { +private: + int m_id; + + std::vector m_trigger_contents; + std::vector m_required_neighbors; + float m_trigger_interval; + u32 m_trigger_chance; + bool m_simple_catch_up; + s16 m_min_y; + s16 m_max_y; +public: + LuaABM(int id, + const std::vector &trigger_contents, + const std::vector &required_neighbors, + float trigger_interval, u32 trigger_chance, bool simple_catch_up, + s16 min_y, s16 max_y): + m_id(id), + m_trigger_contents(trigger_contents), + m_required_neighbors(required_neighbors), + m_trigger_interval(trigger_interval), + m_trigger_chance(trigger_chance), + m_simple_catch_up(simple_catch_up), + m_min_y(min_y), + m_max_y(max_y) + { + } + virtual const std::vector &getTriggerContents() const + { + return m_trigger_contents; + } + virtual const std::vector &getRequiredNeighbors() const + { + return m_required_neighbors; + } + virtual float getTriggerInterval() + { + return m_trigger_interval; + } + virtual u32 getTriggerChance() + { + return m_trigger_chance; + } + virtual bool getSimpleCatchUp() + { + return m_simple_catch_up; + } + virtual s16 getMinY() + { + return m_min_y; + } + virtual s16 getMaxY() + { + return m_max_y; + } + + virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n, + u32 active_object_count, u32 active_object_count_wider) + { + auto *script = env->getScriptIface(); + script->triggerABM(m_id, p, n, active_object_count, active_object_count_wider); + } +}; + +class LuaLBM : public LoadingBlockModifierDef +{ +private: + int m_id; +public: + LuaLBM(int id, + const std::vector &trigger_contents, + const std::string &name, bool run_at_every_load): + m_id(id) + { + this->run_at_every_load = run_at_every_load; + this->trigger_contents = trigger_contents; + this->name = name; + } + + virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n, float dtime_s) + { + auto *script = env->getScriptIface(); + script->triggerLBM(m_id, p, n, dtime_s); + } +}; + +/* + ScriptApiEnv +*/ void ScriptApiEnv::environment_OnGenerated(v3s16 minp, v3s16 maxp, u32 blockseed) @@ -46,7 +140,6 @@ void ScriptApiEnv::environment_OnGenerated(v3s16 minp, v3s16 maxp, void ScriptApiEnv::environment_Step(float dtime) { SCRIPTAPI_PRECHECKHEADER - //infostream << "scriptapi_environment_step" << std::endl; // Get core.registered_globalsteps lua_getglobal(L, "core"); @@ -76,12 +169,40 @@ void ScriptApiEnv::player_event(ServerActiveObject *player, const std::string &t void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) { SCRIPTAPI_PRECHECKHEADER + + assert(env); verbosestream << "ScriptApiEnv: Environment initialized" << std::endl; setEnv(env); - /* - Add {Loading,Active}BlockModifiers to environment - */ + readABMs(); + readLBMs(); +} + +// Reads a single or a list of node names into a vector +bool ScriptApiEnv::read_nodenames(lua_State *L, int idx, std::vector &to) +{ + if (lua_istable(L, idx)) { + const int table = idx < 0 ? (lua_gettop(L) + idx + 1) : idx; + lua_pushnil(L); + while (lua_next(L, table)) { + // key at index -2 and value at index -1 + luaL_checktype(L, -1, LUA_TSTRING); + to.emplace_back(readParam(L, -1)); + // removes value, keeps key for next iteration + lua_pop(L, 1); + } + } else if (lua_isstring(L, idx)) { + to.emplace_back(readParam(L, idx)); + } else { + return false; + } + return true; +} + +void ScriptApiEnv::readABMs() +{ + SCRIPTAPI_PRECHECKHEADER + auto *env = reinterpret_cast(getEnv()); // Get core.registered_abms lua_getglobal(L, "core"); @@ -100,36 +221,12 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) std::vector trigger_contents; lua_getfield(L, current_abm, "nodenames"); - if (lua_istable(L, -1)) { - int table = lua_gettop(L); - lua_pushnil(L); - while (lua_next(L, table)) { - // key at index -2 and value at index -1 - luaL_checktype(L, -1, LUA_TSTRING); - trigger_contents.emplace_back(readParam(L, -1)); - // removes value, keeps key for next iteration - lua_pop(L, 1); - } - } else if (lua_isstring(L, -1)) { - trigger_contents.emplace_back(readParam(L, -1)); - } + read_nodenames(L, -1, trigger_contents); lua_pop(L, 1); std::vector required_neighbors; lua_getfield(L, current_abm, "neighbors"); - if (lua_istable(L, -1)) { - int table = lua_gettop(L); - lua_pushnil(L); - while (lua_next(L, table)) { - // key at index -2 and value at index -1 - luaL_checktype(L, -1, LUA_TSTRING); - required_neighbors.emplace_back(readParam(L, -1)); - // removes value, keeps key for next iteration - lua_pop(L, 1); - } - } else if (lua_isstring(L, -1)) { - required_neighbors.emplace_back(readParam(L, -1)); - } + read_nodenames(L, -1, required_neighbors); lua_pop(L, 1); float trigger_interval = 10.0; @@ -151,7 +248,7 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) luaL_checktype(L, current_abm + 1, LUA_TFUNCTION); lua_pop(L, 1); - LuaABM *abm = new LuaABM(L, id, trigger_contents, required_neighbors, + LuaABM *abm = new LuaABM(id, trigger_contents, required_neighbors, trigger_interval, trigger_chance, simple_catch_up, min_y, max_y); env->addActiveBlockModifier(abm); @@ -160,6 +257,12 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) lua_pop(L, 1); } lua_pop(L, 1); +} + +void ScriptApiEnv::readLBMs() +{ + SCRIPTAPI_PRECHECKHEADER + auto *env = reinterpret_cast(getEnv()); // Get core.registered_lbms lua_getglobal(L, "core"); @@ -177,21 +280,9 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) int id = lua_tonumber(L, -2); int current_lbm = lua_gettop(L); - std::set trigger_contents; + std::vector trigger_contents; lua_getfield(L, current_lbm, "nodenames"); - if (lua_istable(L, -1)) { - int table = lua_gettop(L); - lua_pushnil(L); - while (lua_next(L, table)) { - // key at index -2 and value at index -1 - luaL_checktype(L, -1, LUA_TSTRING); - trigger_contents.insert(readParam(L, -1)); - // removes value, keeps key for next iteration - lua_pop(L, 1); - } - } else if (lua_isstring(L, -1)) { - trigger_contents.insert(readParam(L, -1)); - } + read_nodenames(L, -1, trigger_contents); lua_pop(L, 1); std::string name; @@ -204,7 +295,7 @@ void ScriptApiEnv::initializeEnvironment(ServerEnvironment *env) luaL_checktype(L, current_lbm + 1, LUA_TFUNCTION); lua_pop(L, 1); - LuaLBM *lbm = new LuaLBM(L, id, trigger_contents, name, + LuaLBM *lbm = new LuaLBM(id, trigger_contents, name, run_at_every_load); env->addLoadingBlockModifierDef(lbm); @@ -288,7 +379,7 @@ void ScriptApiEnv::on_liquid_transformed( int index = 1; lua_createtable(L, list.size(), 0); lua_createtable(L, list.size(), 0); - for(std::pair p : list) { + for(auto &p : list) { lua_pushnumber(L, index); push_v3s16(L, p.first); lua_rawset(L, -4); @@ -332,3 +423,78 @@ bool ScriptApiEnv::has_on_mapblocks_changed() luaL_checktype(L, -1, LUA_TTABLE); return lua_objlen(L, -1) > 0; } + +void ScriptApiEnv::triggerABM(int id, v3s16 p, MapNode n, + u32 active_object_count, u32 active_object_count_wider) +{ + SCRIPTAPI_PRECHECKHEADER + + int error_handler = PUSH_ERROR_HANDLER(L); + + // Get registered_abms + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_abms"); + luaL_checktype(L, -1, LUA_TTABLE); + lua_remove(L, -2); // Remove core + + // Get registered_abms[m_id] + lua_pushinteger(L, id); + lua_gettable(L, -2); + FATAL_ERROR_IF(lua_isnil(L, -1), "Entry with given id not found in registered_abms table"); + lua_remove(L, -2); // Remove registered_abms + + setOriginFromTable(-1); + + // Call action + luaL_checktype(L, -1, LUA_TTABLE); + lua_getfield(L, -1, "action"); + luaL_checktype(L, -1, LUA_TFUNCTION); + lua_remove(L, -2); // Remove registered_abms[m_id] + push_v3s16(L, p); + pushnode(L, n); + lua_pushnumber(L, active_object_count); + lua_pushnumber(L, active_object_count_wider); + + int result = lua_pcall(L, 4, 0, error_handler); + if (result) + scriptError(result, "LuaABM::trigger"); + + lua_pop(L, 1); // Pop error handler +} + +void ScriptApiEnv::triggerLBM(int id, v3s16 p, + const MapNode n, const float dtime_s) +{ + SCRIPTAPI_PRECHECKHEADER + + int error_handler = PUSH_ERROR_HANDLER(L); + + // Get registered_lbms + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_lbms"); + luaL_checktype(L, -1, LUA_TTABLE); + lua_remove(L, -2); // Remove core + + // Get registered_lbms[m_id] + lua_pushinteger(L, id); + lua_gettable(L, -2); + FATAL_ERROR_IF(lua_isnil(L, -1), "Entry with given id not found in registered_lbms table"); + lua_remove(L, -2); // Remove registered_lbms + + setOriginFromTable(-1); + + // Call action + luaL_checktype(L, -1, LUA_TTABLE); + lua_getfield(L, -1, "action"); + luaL_checktype(L, -1, LUA_TFUNCTION); + lua_remove(L, -2); // Remove registered_lbms[m_id] + push_v3s16(L, p); + pushnode(L, n); + lua_pushnumber(L, dtime_s); + + int result = lua_pcall(L, 3, 0, error_handler); + if (result) + scriptError(result, "LuaLBM::trigger"); + + lua_pop(L, 1); // Pop error handler +} diff --git a/src/script/cpp_api/s_env.h b/src/script/cpp_api/s_env.h index bc4c4cd4d..8a88749fa 100644 --- a/src/script/cpp_api/s_env.h +++ b/src/script/cpp_api/s_env.h @@ -55,5 +55,19 @@ public: // Determines whether there are any on_mapblocks_changed callbacks bool has_on_mapblocks_changed(); + // Initializes environment and loads some definitions from Lua void initializeEnvironment(ServerEnvironment *env); + + void triggerABM(int id, v3s16 p, MapNode n, + u32 active_object_count, u32 active_object_count_wider); + + void triggerLBM(int id, v3s16 p, MapNode n, float dtime_s); + +private: + void readABMs(); + + void readLBMs(); + + // Reads a single or a list of node names into a vector + static bool read_nodenames(lua_State *L, int idx, std::vector &to); }; diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index f5ed2804c..6fd0e2b2a 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -65,93 +65,6 @@ const EnumString ModApiEnvBase::es_BlockStatusType[] = /////////////////////////////////////////////////////////////////////////////// - -void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n, - u32 active_object_count, u32 active_object_count_wider) -{ - ServerScripting *scriptIface = env->getScriptIface(); - scriptIface->realityCheck(); - - lua_State *L = scriptIface->getStack(); - sanity_check(lua_checkstack(L, 20)); - StackUnroller stack_unroller(L); - - int error_handler = PUSH_ERROR_HANDLER(L); - - // Get registered_abms - lua_getglobal(L, "core"); - lua_getfield(L, -1, "registered_abms"); - luaL_checktype(L, -1, LUA_TTABLE); - lua_remove(L, -2); // Remove core - - // Get registered_abms[m_id] - lua_pushinteger(L, m_id); - lua_gettable(L, -2); - if(lua_isnil(L, -1)) - FATAL_ERROR(""); - lua_remove(L, -2); // Remove registered_abms - - scriptIface->setOriginFromTable(-1); - - // Call action - luaL_checktype(L, -1, LUA_TTABLE); - lua_getfield(L, -1, "action"); - luaL_checktype(L, -1, LUA_TFUNCTION); - lua_remove(L, -2); // Remove registered_abms[m_id] - push_v3s16(L, p); - pushnode(L, n); - lua_pushnumber(L, active_object_count); - lua_pushnumber(L, active_object_count_wider); - - int result = lua_pcall(L, 4, 0, error_handler); - if (result) - scriptIface->scriptError(result, "LuaABM::trigger"); - - lua_pop(L, 1); // Pop error handler -} - -void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, - const MapNode n, const float dtime_s) -{ - ServerScripting *scriptIface = env->getScriptIface(); - scriptIface->realityCheck(); - - lua_State *L = scriptIface->getStack(); - sanity_check(lua_checkstack(L, 20)); - StackUnroller stack_unroller(L); - - int error_handler = PUSH_ERROR_HANDLER(L); - - // Get registered_lbms - lua_getglobal(L, "core"); - lua_getfield(L, -1, "registered_lbms"); - luaL_checktype(L, -1, LUA_TTABLE); - lua_remove(L, -2); // Remove core - - // Get registered_lbms[m_id] - lua_pushinteger(L, m_id); - lua_gettable(L, -2); - FATAL_ERROR_IF(lua_isnil(L, -1), "Entry with given id not found in registered_lbms table"); - lua_remove(L, -2); // Remove registered_lbms - - scriptIface->setOriginFromTable(-1); - - // Call action - luaL_checktype(L, -1, LUA_TTABLE); - lua_getfield(L, -1, "action"); - luaL_checktype(L, -1, LUA_TFUNCTION); - lua_remove(L, -2); // Remove registered_lbms[m_id] - push_v3s16(L, p); - pushnode(L, n); - lua_pushnumber(L, dtime_s); - - int result = lua_pcall(L, 3, 0, error_handler); - if (result) - scriptIface->scriptError(result, "LuaLBM::trigger"); - - lua_pop(L, 1); // Pop error handler -} - int LuaRaycast::l_next(lua_State *L) { GET_PLAIN_ENV_PTR; diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h index 2ed0eb114..b92a6f935 100644 --- a/src/script/lua_api/l_env.h +++ b/src/script/lua_api/l_env.h @@ -20,9 +20,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once #include "lua_api/l_base.h" -#include "serverenvironment.h" #include "raycast.h" +class ServerScripting; + // base class containing helpers class ModApiEnvBase : public ModApiBase { protected: @@ -281,82 +282,6 @@ public: static void InitializeEmerge(lua_State *L, int top); }; -class LuaABM : public ActiveBlockModifier { -private: - int m_id; - - std::vector m_trigger_contents; - std::vector m_required_neighbors; - float m_trigger_interval; - u32 m_trigger_chance; - bool m_simple_catch_up; - s16 m_min_y; - s16 m_max_y; -public: - LuaABM(lua_State *L, int id, - const std::vector &trigger_contents, - const std::vector &required_neighbors, - float trigger_interval, u32 trigger_chance, bool simple_catch_up, s16 min_y, s16 max_y): - m_id(id), - m_trigger_contents(trigger_contents), - m_required_neighbors(required_neighbors), - m_trigger_interval(trigger_interval), - m_trigger_chance(trigger_chance), - m_simple_catch_up(simple_catch_up), - m_min_y(min_y), - m_max_y(max_y) - { - } - virtual const std::vector &getTriggerContents() const - { - return m_trigger_contents; - } - virtual const std::vector &getRequiredNeighbors() const - { - return m_required_neighbors; - } - virtual float getTriggerInterval() - { - return m_trigger_interval; - } - virtual u32 getTriggerChance() - { - return m_trigger_chance; - } - virtual bool getSimpleCatchUp() - { - return m_simple_catch_up; - } - virtual s16 getMinY() - { - return m_min_y; - } - virtual s16 getMaxY() - { - return m_max_y; - } - virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n, - u32 active_object_count, u32 active_object_count_wider); -}; - -class LuaLBM : public LoadingBlockModifierDef -{ -private: - int m_id; -public: - LuaLBM(lua_State *L, int id, - const std::set &trigger_contents, - const std::string &name, - bool run_at_every_load): - m_id(id) - { - this->run_at_every_load = run_at_every_load; - this->trigger_contents = trigger_contents; - this->name = name; - } - virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n, float dtime_s); -}; - //! Lua wrapper for RaycastState objects class LuaRaycast : public ModApiBase { diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index 24e4a587e..f79102e74 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -77,11 +77,11 @@ ABMWithState::ABMWithState(ActiveBlockModifier *abm_): LBMManager */ -void LBMContentMapping::deleteContents() +LBMContentMapping::~LBMContentMapping() { - for (auto &it : lbm_list) { + map.clear(); + for (auto &it : lbm_list) delete it; - } } void LBMContentMapping::addLBM(LoadingBlockModifierDef *lbm_def, IGameDef *gamedef) @@ -90,29 +90,32 @@ void LBMContentMapping::addLBM(LoadingBlockModifierDef *lbm_def, IGameDef *gamed // Unknown names get added to the global NameIdMapping. const NodeDefManager *nodedef = gamedef->ndef(); + FATAL_ERROR_IF(CONTAINS(lbm_list, lbm_def), "Same LBM registered twice"); lbm_list.push_back(lbm_def); - for (const std::string &nodeTrigger: lbm_def->trigger_contents) { - std::vector c_ids; - bool found = nodedef->getIds(nodeTrigger, c_ids); + std::vector c_ids; + + for (const auto &node : lbm_def->trigger_contents) { + bool found = nodedef->getIds(node, c_ids); if (!found) { - content_t c_id = gamedef->allocateUnknownNodeId(nodeTrigger); + content_t c_id = gamedef->allocateUnknownNodeId(node); if (c_id == CONTENT_IGNORE) { // Seems it can't be allocated. - warningstream << "Could not internalize node name \"" << nodeTrigger + warningstream << "Could not internalize node name \"" << node << "\" while loading LBM \"" << lbm_def->name << "\"." << std::endl; continue; } c_ids.push_back(c_id); } - - for (content_t c_id : c_ids) { - map[c_id].push_back(lbm_def); - } } + + SORT_AND_UNIQUE(c_ids); + + for (content_t c_id : c_ids) + map[c_id].push_back(lbm_def); } -const std::vector * +const LBMContentMapping::lbm_vector * LBMContentMapping::lookup(content_t c) const { lbm_map::const_iterator it = map.find(c); @@ -130,9 +133,7 @@ LBMManager::~LBMManager() delete m_lbm_def.second; } - for (auto &it : m_lbm_lookup) { - (it.second).deleteContents(); - } + m_lbm_lookup.clear(); } void LBMManager::addLBMDef(LoadingBlockModifierDef *lbm_def) @@ -236,7 +237,7 @@ std::string LBMManager::createIntroductionTimesString() std::ostringstream oss; for (const auto &it : m_lbm_lookup) { u32 time = it.first; - const std::vector &lbm_list = it.second.lbm_list; + auto &lbm_list = it.second.getList(); for (const auto &lbm_def : lbm_list) { // Don't add if the LBM runs at every load, // then introducement time is hardcoded @@ -255,16 +256,17 @@ void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, // Precondition, we need m_lbm_lookup to be initialized FATAL_ERROR_IF(!m_query_mode, "attempted to query on non fully set up LBMManager"); - v3s16 pos_of_block = block->getPosRelative(); + + const v3s16 pos_of_block = block->getPosRelative(); v3s16 pos; MapNode n; content_t c; auto it = getLBMsIntroducedAfter(stamp); + // Note: the iteration count of this outer loop is typically very low, so it's ok. for (; it != m_lbm_lookup.end(); ++it) { - // Cache previous version to speedup lookup which has a very high performance - // penalty on each call + // Cache previous lookup result since it has a high performance penalty. content_t previous_c = CONTENT_IGNORE; - const std::vector *lbm_list = nullptr; + const LBMContentMapping::lbm_vector *lbm_list = nullptr; for (pos.Z = 0; pos.Z < MAP_BLOCKSIZE; pos.Z++) for (pos.Y = 0; pos.Y < MAP_BLOCKSIZE; pos.Y++) @@ -272,7 +274,6 @@ void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block, n = block->getNodeNoCheck(pos); c = n.getContent(); - // If content_t are not matching perform an LBM lookup if (previous_c != c) { lbm_list = it->second.lookup(c); previous_c = c; @@ -792,11 +793,9 @@ void ServerEnvironment::loadDefaultMeta() struct ActiveABM { ActiveBlockModifier *abm; - int chance; std::vector required_neighbors; - bool check_required_neighbors; // false if required_neighbors is known to be empty - s16 min_y; - s16 max_y; + int chance; + s16 min_y, max_y; }; #define CONTENT_TYPE_CACHE_MAX 64 @@ -812,16 +811,16 @@ public: bool use_timers): m_env(env) { - if(dtime_s < 0.001) + if (dtime_s < 0.001f) return; const NodeDefManager *ndef = env->getGameDef()->ndef(); for (ABMWithState &abmws : abms) { ActiveBlockModifier *abm = abmws.abm; float trigger_interval = abm->getTriggerInterval(); - if(trigger_interval < 0.001) - trigger_interval = 0.001; + if (trigger_interval < 0.001f) + trigger_interval = 0.001f; float actual_interval = dtime_s; - if(use_timers){ + if (use_timers) { abmws.timer += dtime_s; if(abmws.timer < trigger_interval) continue; @@ -831,6 +830,7 @@ public: float chance = abm->getTriggerChance(); if (chance == 0) chance = 1; + ActiveABM aabm; aabm.abm = abm; if (abm->getSimpleCatchUp()) { @@ -848,25 +848,21 @@ public: aabm.max_y = abm->getMaxY(); // Trigger neighbors - const std::vector &required_neighbors_s = - abm->getRequiredNeighbors(); - for (const std::string &required_neighbor_s : required_neighbors_s) { - ndef->getIds(required_neighbor_s, aabm.required_neighbors); - } - aabm.check_required_neighbors = !required_neighbors_s.empty(); + for (const auto &s : abm->getRequiredNeighbors()) + ndef->getIds(s, aabm.required_neighbors); + SORT_AND_UNIQUE(aabm.required_neighbors); // Trigger contents - const std::vector &contents_s = abm->getTriggerContents(); - for (const std::string &content_s : contents_s) { - std::vector ids; - ndef->getIds(content_s, ids); - for (content_t c : ids) { - if (c >= m_aabms.size()) - m_aabms.resize(c + 256, NULL); - if (!m_aabms[c]) - m_aabms[c] = new std::vector; - m_aabms[c]->push_back(aabm); - } + std::vector ids; + for (const auto &s : abm->getTriggerContents()) + ndef->getIds(s, ids); + SORT_AND_UNIQUE(ids); + for (content_t c : ids) { + if (c >= m_aabms.size()) + m_aabms.resize(c + 256, nullptr); + if (!m_aabms[c]) + m_aabms[c] = new std::vector; + m_aabms[c]->push_back(aabm); } } } @@ -967,7 +963,7 @@ public: continue; // Check neighbors - if (aabm.check_required_neighbors) { + if (!aabm.required_neighbors.empty()) { v3s16 p1; for(p1.X = p0.X-1; p1.X <= p0.X+1; p1.X++) for(p1.Y = p0.Y-1; p1.Y <= p0.Y+1; p1.Y++) diff --git a/src/serverenvironment.h b/src/serverenvironment.h index 7a388d21c..51d699cab 100644 --- a/src/serverenvironment.h +++ b/src/serverenvironment.h @@ -90,7 +90,7 @@ struct ABMWithState struct LoadingBlockModifierDef { // Set of contents to trigger on - std::set trigger_contents; + std::vector trigger_contents; std::string name; bool run_at_every_load = false; @@ -100,19 +100,25 @@ struct LoadingBlockModifierDef MapNode n, float dtime_s) {}; }; -struct LBMContentMapping +class LBMContentMapping { - typedef std::unordered_map> lbm_map; - lbm_map map; +public: + typedef std::vector lbm_vector; + typedef std::unordered_map lbm_map; - std::vector lbm_list; - - // Needs to be separate method (not inside destructor), - // because the LBMContentMapping may be copied and destructed - // many times during operation in the lbm_lookup_map. - void deleteContents(); + LBMContentMapping() = default; void addLBM(LoadingBlockModifierDef *lbm_def, IGameDef *gamedef); const lbm_map::mapped_type *lookup(content_t c) const; + const lbm_vector &getList() const { return lbm_list; } + + // This struct owns the LBM pointers. + ~LBMContentMapping(); + DISABLE_CLASS_COPY(LBMContentMapping); + ALLOW_CLASS_MOVE(LBMContentMapping); + +private: + lbm_vector lbm_list; + lbm_map map; }; class LBMManager diff --git a/src/util/basic_macros.h b/src/util/basic_macros.h index 7c3746417..f0fd4eb48 100644 --- a/src/util/basic_macros.h +++ b/src/util/basic_macros.h @@ -28,6 +28,12 @@ with this program; if not, write to the Free Software Foundation, Inc., // Requires #define CONTAINS(c, v) (std::find((c).begin(), (c).end(), (v)) != (c).end()) +// Requires +#define SORT_AND_UNIQUE(c) do { \ + std::sort((c).begin(), (c).end()); \ + (c).erase(std::unique((c).begin(), (c).end()), (c).end()); \ + } while (0) + // To disable copy constructors and assignment operations for some class // 'Foobar', add the macro DISABLE_CLASS_COPY(Foobar) in the class definition. // Note this also disables copying for any classes derived from 'Foobar' as well