mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
Bulk LBMs (#14954)
This commit is contained in:
parent
7ae51382c8
commit
811adf5d42
9 changed files with 126 additions and 49 deletions
|
@ -111,10 +111,11 @@ public:
|
|||
this->name = name;
|
||||
}
|
||||
|
||||
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n, float dtime_s)
|
||||
virtual void trigger(ServerEnvironment *env, MapBlock *block,
|
||||
const std::unordered_set<v3s16> &positions, float dtime_s)
|
||||
{
|
||||
auto *script = env->getScriptIface();
|
||||
script->triggerLBM(m_id, p, n, dtime_s);
|
||||
script->triggerLBM(m_id, block, positions, dtime_s);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -291,10 +292,6 @@ void ScriptApiEnv::readLBMs()
|
|||
bool run_at_every_load = getboolfield_default(L, current_lbm,
|
||||
"run_at_every_load", false);
|
||||
|
||||
lua_getfield(L, current_lbm, "action");
|
||||
luaL_checktype(L, current_lbm + 1, LUA_TFUNCTION);
|
||||
lua_pop(L, 1);
|
||||
|
||||
LuaLBM *lbm = new LuaLBM(id, trigger_contents, name,
|
||||
run_at_every_load);
|
||||
|
||||
|
@ -462,34 +459,29 @@ void ScriptApiEnv::triggerABM(int id, v3s16 p, MapNode n,
|
|||
lua_pop(L, 1); // Pop error handler
|
||||
}
|
||||
|
||||
void ScriptApiEnv::triggerLBM(int id, v3s16 p,
|
||||
const MapNode n, const float dtime_s)
|
||||
void ScriptApiEnv::triggerLBM(int id, MapBlock *block,
|
||||
const std::unordered_set<v3s16> &positions, float dtime_s)
|
||||
{
|
||||
SCRIPTAPI_PRECHECKHEADER
|
||||
|
||||
int error_handler = PUSH_ERROR_HANDLER(L);
|
||||
|
||||
// Get registered_lbms
|
||||
const v3s16 pos_of_block = block->getPosRelative();
|
||||
|
||||
// Get core.run_lbm
|
||||
lua_getglobal(L, "core");
|
||||
lua_getfield(L, -1, "registered_lbms");
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
lua_getfield(L, -1, "run_lbm");
|
||||
luaL_checktype(L, -1, LUA_TFUNCTION);
|
||||
lua_remove(L, -2); // Remove core
|
||||
|
||||
// Get registered_lbms[m_id]
|
||||
// Call it
|
||||
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_createtable(L, positions.size(), 0);
|
||||
int i = 1;
|
||||
for (auto &p : positions) {
|
||||
push_v3s16(L, pos_of_block + p);
|
||||
lua_rawseti(L, -2, i++);
|
||||
}
|
||||
lua_pushnumber(L, dtime_s);
|
||||
|
||||
int result = lua_pcall(L, 3, 0, error_handler);
|
||||
|
|
|
@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include <vector>
|
||||
|
||||
class ServerEnvironment;
|
||||
class MapBlock;
|
||||
struct ScriptCallbackState;
|
||||
|
||||
class ScriptApiEnv : virtual public ScriptApiBase
|
||||
|
@ -61,7 +62,8 @@ public:
|
|||
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);
|
||||
void triggerLBM(int id, MapBlock *block,
|
||||
const std::unordered_set<v3s16> &positions, float dtime_s);
|
||||
|
||||
private:
|
||||
void readABMs();
|
||||
|
|
|
@ -257,40 +257,73 @@ void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block,
|
|||
FATAL_ERROR_IF(!m_query_mode,
|
||||
"attempted to query on non fully set up LBMManager");
|
||||
|
||||
const v3s16 pos_of_block = block->getPosRelative();
|
||||
v3s16 pos;
|
||||
MapNode n;
|
||||
content_t c;
|
||||
auto it = getLBMsIntroducedAfter(stamp);
|
||||
// Collect a list of all LBMs and associated positions
|
||||
struct LBMToRun {
|
||||
std::unordered_set<v3s16> p; // node positions
|
||||
std::unordered_set<LoadingBlockModifierDef*> l;
|
||||
};
|
||||
std::unordered_map<content_t, LBMToRun> to_run;
|
||||
|
||||
// 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 lookup result since it has a high performance penalty.
|
||||
for (auto it = getLBMsIntroducedAfter(stamp); it != m_lbm_lookup.end(); ++it) {
|
||||
v3s16 pos;
|
||||
content_t c;
|
||||
|
||||
// Cache previous lookups since it has a high performance penalty.
|
||||
content_t previous_c = CONTENT_IGNORE;
|
||||
const LBMContentMapping::lbm_vector *lbm_list = nullptr;
|
||||
LBMToRun *batch = nullptr;
|
||||
|
||||
for (pos.Z = 0; pos.Z < MAP_BLOCKSIZE; pos.Z++)
|
||||
for (pos.Y = 0; pos.Y < MAP_BLOCKSIZE; pos.Y++)
|
||||
for (pos.X = 0; pos.X < MAP_BLOCKSIZE; pos.X++) {
|
||||
n = block->getNodeNoCheck(pos);
|
||||
c = n.getContent();
|
||||
c = block->getNodeNoCheck(pos).getContent();
|
||||
|
||||
bool c_changed = false;
|
||||
if (previous_c != c) {
|
||||
c_changed = true;
|
||||
lbm_list = it->second.lookup(c);
|
||||
batch = &to_run[c];
|
||||
previous_c = c;
|
||||
}
|
||||
|
||||
if (!lbm_list)
|
||||
continue;
|
||||
for (auto lbmdef : *lbm_list) {
|
||||
lbmdef->trigger(env, pos + pos_of_block, n, dtime_s);
|
||||
if (block->isOrphan())
|
||||
return;
|
||||
n = block->getNodeNoCheck(pos);
|
||||
if (n.getContent() != c)
|
||||
break; // The node was changed and the LBMs no longer apply
|
||||
batch->p.insert(pos);
|
||||
if (c_changed) {
|
||||
batch->l.insert(lbm_list->begin(), lbm_list->end());
|
||||
} else {
|
||||
// we were here before so the list must be filled
|
||||
assert(!batch->l.empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actually run them
|
||||
bool first = true;
|
||||
for (auto &[c, batch] : to_run) {
|
||||
for (auto &lbm_def : batch.l) {
|
||||
if (!first) {
|
||||
// The fun part: since any LBM call can change the nodes inside of he
|
||||
// block, we have to recheck the positions to see if the wanted node
|
||||
// is still there.
|
||||
// Note that we don't rescan the whole block, we don't want to include new changes.
|
||||
for (auto it2 = batch.p.begin(); it2 != batch.p.end(); ) {
|
||||
if (block->getNodeNoCheck(*it2).getContent() != c)
|
||||
it2 = batch.p.erase(it2);
|
||||
else
|
||||
++it2;
|
||||
}
|
||||
}
|
||||
first = false;
|
||||
|
||||
if (batch.p.empty())
|
||||
break;
|
||||
lbm_def->trigger(env, block, batch.p, dtime_s);
|
||||
if (block->isOrphan())
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -96,8 +96,13 @@ struct LoadingBlockModifierDef
|
|||
|
||||
virtual ~LoadingBlockModifierDef() = default;
|
||||
|
||||
virtual void trigger(ServerEnvironment *env, v3s16 p,
|
||||
MapNode n, float dtime_s) {};
|
||||
/// @brief Called to invoke LBM
|
||||
/// @param env environment
|
||||
/// @param block the block in question
|
||||
/// @param positions set of node positions (block-relative!)
|
||||
/// @param dtime_s game time since last deactivation
|
||||
virtual void trigger(ServerEnvironment *env, MapBlock *block,
|
||||
const std::unordered_set<v3s16> &positions, float dtime_s) {};
|
||||
};
|
||||
|
||||
class LBMContentMapping
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue