mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
Merge 636c603946
into 81d62d01d1
This commit is contained in:
commit
1a53032508
15 changed files with 233 additions and 43 deletions
|
@ -47,6 +47,7 @@ core.features = {
|
|||
particle_blend_clip = true,
|
||||
remove_item_match_meta = true,
|
||||
httpfetch_additional_methods = true,
|
||||
abm_changeable = true,
|
||||
}
|
||||
|
||||
function core.has_feature(arg)
|
||||
|
|
|
@ -14,6 +14,8 @@ core.unregister_item_raw = nil
|
|||
local register_alias_raw = core.register_alias_raw
|
||||
core.register_alias_raw = nil
|
||||
|
||||
local override_abm_raw = core.override_abm
|
||||
|
||||
--
|
||||
-- Item / entity / ABM / LBM registration functions
|
||||
--
|
||||
|
@ -100,6 +102,19 @@ function core.register_abm(spec)
|
|||
spec.mod_origin = core.get_current_modname() or "??"
|
||||
end
|
||||
|
||||
function core.override_abm(name, redef)
|
||||
for id, abm in pairs(core.registered_abms) do
|
||||
if abm.name == name then
|
||||
for key, value in pairs(redef) do
|
||||
abm[key] = redef[key]
|
||||
end
|
||||
override_abm_raw(id, abm)
|
||||
return
|
||||
end
|
||||
end
|
||||
core.log("error", "ABM '"..name.."' not found.")
|
||||
end
|
||||
|
||||
function core.register_lbm(spec)
|
||||
-- Add to core.registered_lbms
|
||||
check_modname_prefix(spec.name)
|
||||
|
|
|
@ -5810,6 +5810,8 @@ Utilities
|
|||
remove_item_match_meta = true,
|
||||
-- The HTTP API supports the HEAD and PATCH methods (5.12.0)
|
||||
httpfetch_additional_methods = true,
|
||||
-- Registered and named ABM can be changed on fly (5.13.0)
|
||||
abm_changeable = true,
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -6034,6 +6036,9 @@ Call these functions only at load time!
|
|||
according to its nature (e.g. `core.registered_nodes`)
|
||||
* `core.register_entity(name, entity definition)`
|
||||
* `core.register_abm(abm definition)`
|
||||
* `core.override_abm(name, new_values)`
|
||||
* Change registered ABM
|
||||
* Only on fields mentonied as changeable can be changed.
|
||||
* `core.register_lbm(lbm definition)`
|
||||
* `core.register_alias(alias, original_name)`
|
||||
* Also use this to set the 'mapgen aliases' needed in a game for the core
|
||||
|
@ -9587,6 +9592,10 @@ in active mapblocks.
|
|||
|
||||
```lua
|
||||
{
|
||||
name = "".
|
||||
-- Optional name of ABM.
|
||||
-- ABM with name can be changed at runtime (See `core.override_abm`).
|
||||
|
||||
label = "Lava cooling",
|
||||
-- Descriptive label for profiling purposes (optional).
|
||||
-- Definitions with identical labels will be listed as one.
|
||||
|
@ -9608,14 +9617,18 @@ in active mapblocks.
|
|||
|
||||
interval = 10.0,
|
||||
-- Operation interval in seconds
|
||||
-- This value can be changed by `core.override_abm` call.
|
||||
|
||||
chance = 50,
|
||||
-- Probability of triggering `action` per-node per-interval is 1.0 / chance (integers only)
|
||||
-- This value can be changed by `core.override_abm` call.
|
||||
-- If chance is set to 0, ABM is disabled.
|
||||
|
||||
min_y = -32768,
|
||||
max_y = 32767,
|
||||
-- min and max height levels where ABM will be processed (inclusive)
|
||||
-- can be used to reduce CPU usage
|
||||
-- This value can be changed by `core.override_abm` call.
|
||||
|
||||
catch_up = true,
|
||||
-- If true, catch-up behavior is enabled: The `chance` value is
|
||||
|
@ -9631,6 +9644,7 @@ in active mapblocks.
|
|||
-- mapblock plus all 26 neighboring mapblocks. If any neighboring
|
||||
-- mapblocks are unloaded an estimate is calculated for them based on
|
||||
-- loaded mapblocks.
|
||||
-- This function can be changed by `core.override_abm` call.
|
||||
}
|
||||
```
|
||||
|
||||
|
|
50
games/devtest/mods/testabms/changeable.lua
Normal file
50
games/devtest/mods/testabms/changeable.lua
Normal file
|
@ -0,0 +1,50 @@
|
|||
local abm_first_run = false
|
||||
|
||||
minetest.register_chatcommand("changeableABM", {
|
||||
params = "enable | disable | interval_1 | interval_5",
|
||||
description = "Active/Deactivate changeable ABM.",
|
||||
func = function(name, param)
|
||||
if param == "enable" then
|
||||
minetest.override_abm("testchangeableabm:abm", {
|
||||
interval = 30.0,
|
||||
chance = 1,
|
||||
})
|
||||
abm_first_run = true
|
||||
return true, "ABM has been enabled."
|
||||
elseif param == "interval_1" then
|
||||
minetest.override_abm("testchangeableabm:abm", {
|
||||
interval = 1.0,
|
||||
chance = 1,
|
||||
})
|
||||
abm_first_run = true
|
||||
return true, "ABM has been enabled with interval 1."
|
||||
elseif param == "interval_5" then
|
||||
minetest.override_abm("testchangeableabm:abm", {
|
||||
interval = 5.0,
|
||||
chance = 1,
|
||||
})
|
||||
abm_first_run = true
|
||||
return true, "ABM has been enabled with interval 5."
|
||||
elseif param == "disable" then
|
||||
minetest.override_abm("testchangeableabm:abm", {
|
||||
chance = 0,
|
||||
})
|
||||
return true, "ABM has been disabled."
|
||||
else
|
||||
return false, "Check /help changeableABB for allowed parameters."
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
name = "testchangeableabm:abm",
|
||||
nodenames = "basenodes:stone",
|
||||
interval = 30.0,
|
||||
chance = 0, -- as default, ABM is disabled
|
||||
action = function(pos)
|
||||
if abm_first_run then
|
||||
minetest.chat_send_all("Changeable ABM runs first time after enable.")
|
||||
abm_first_run = false
|
||||
end
|
||||
end,
|
||||
})
|
|
@ -5,3 +5,4 @@ dofile(path.."/chances.lua")
|
|||
dofile(path.."/intervals.lua")
|
||||
dofile(path.."/min_max.lua")
|
||||
dofile(path.."/neighbors.lua")
|
||||
dofile(path.."/changeable.lua")
|
||||
|
|
47
games/devtest/mods/unittests/env.lua
Normal file
47
games/devtest/mods/unittests/env.lua
Normal file
|
@ -0,0 +1,47 @@
|
|||
-- Object Passing / Serialization
|
||||
|
||||
local abm_action1 = function ()
|
||||
end
|
||||
local abm_action2 = function ()
|
||||
end
|
||||
|
||||
core.register_abm({
|
||||
name = "unittests:abm",
|
||||
nodenames = "testnodes:stone",
|
||||
interval = 1,
|
||||
chance = 0,
|
||||
min_y = -10,
|
||||
max_y = 20,
|
||||
action = abm_action1
|
||||
})
|
||||
|
||||
local abm_index = #core.registered_abms
|
||||
|
||||
local function test_abm_override()
|
||||
core.override_abm("unittests:abm", {
|
||||
interval = 500,
|
||||
chance = 25,
|
||||
min_y = -100,
|
||||
max_y = 200,
|
||||
action = abm_action2
|
||||
})
|
||||
assert(core.registered_abms[abm_index].interval == 500)
|
||||
assert(core.registered_abms[abm_index].chance == 25)
|
||||
assert(core.registered_abms[abm_index].min_y == -100)
|
||||
assert(core.registered_abms[abm_index].max_y == 200)
|
||||
assert(core.registered_abms[abm_index].action == abm_action2)
|
||||
|
||||
core.override_abm("unittests:abm", {
|
||||
interval = 1,
|
||||
chance = 0,
|
||||
min_y = -10,
|
||||
max_y = 20,
|
||||
action = abm_action1
|
||||
})
|
||||
assert(core.registered_abms[abm_index].interval == 1)
|
||||
assert(core.registered_abms[abm_index].chance == 0)
|
||||
assert(core.registered_abms[abm_index].min_y == -10)
|
||||
assert(core.registered_abms[abm_index].max_y == 20)
|
||||
assert(core.registered_abms[abm_index].action == abm_action1)
|
||||
end
|
||||
unittests.register("test_abm_override", test_abm_override)
|
|
@ -201,6 +201,7 @@ dofile(modpath .. "/inventory.lua")
|
|||
dofile(modpath .. "/load_time.lua")
|
||||
dofile(modpath .. "/on_shutdown.lua")
|
||||
dofile(modpath .. "/color.lua")
|
||||
dofile(modpath .. "/env.lua")
|
||||
|
||||
--------------
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ class LuaABM : public ActiveBlockModifier {
|
|||
private:
|
||||
const int m_id;
|
||||
|
||||
std::string m_name;
|
||||
std::vector<std::string> m_trigger_contents;
|
||||
std::vector<std::string> m_required_neighbors;
|
||||
std::vector<std::string> m_without_neighbors;
|
||||
|
@ -31,12 +32,14 @@ private:
|
|||
s16 m_max_y;
|
||||
public:
|
||||
LuaABM(int id,
|
||||
const std::string name,
|
||||
const std::vector<std::string> &trigger_contents,
|
||||
const std::vector<std::string> &required_neighbors,
|
||||
const std::vector<std::string> &without_neighbors,
|
||||
float trigger_interval, u32 trigger_chance, bool simple_catch_up,
|
||||
s16 min_y, s16 max_y):
|
||||
m_id(id),
|
||||
m_name(name),
|
||||
m_trigger_contents(trigger_contents),
|
||||
m_required_neighbors(required_neighbors),
|
||||
m_without_neighbors(without_neighbors),
|
||||
|
@ -47,6 +50,10 @@ public:
|
|||
m_max_y(max_y)
|
||||
{
|
||||
}
|
||||
virtual const std::string &getName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
virtual const std::vector<std::string> &getTriggerContents() const
|
||||
{
|
||||
return m_trigger_contents;
|
||||
|
@ -79,7 +86,6 @@ public:
|
|||
{
|
||||
return m_max_y;
|
||||
}
|
||||
|
||||
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n,
|
||||
u32 active_object_count, u32 active_object_count_wider)
|
||||
{
|
||||
|
@ -192,6 +198,62 @@ bool ScriptApiEnv::read_nodenames(lua_State *L, int idx, std::vector<std::string
|
|||
return true;
|
||||
}
|
||||
|
||||
int ScriptApiEnv::override_abm(lua_State *L, ServerEnvironment *env)
|
||||
{
|
||||
int abm_id = lua_tonumber(L, 1);
|
||||
|
||||
LuaABM *abm = ScriptApiEnv::readABM(L, 2, abm_id);
|
||||
if (abm != nullptr) {
|
||||
env->replaceActiveBlockModifier(abm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LuaABM *ScriptApiEnv::readABM(lua_State *L, int abm_index, int id)
|
||||
{
|
||||
std::string name;
|
||||
getstringfield(L, abm_index, "name", name);
|
||||
|
||||
std::vector<std::string> trigger_contents;
|
||||
lua_getfield(L, abm_index, "nodenames");
|
||||
read_nodenames(L, -1, trigger_contents);
|
||||
lua_pop(L, 1);
|
||||
|
||||
std::vector<std::string> required_neighbors;
|
||||
lua_getfield(L, abm_index, "neighbors");
|
||||
read_nodenames(L, -1, required_neighbors);
|
||||
lua_pop(L, 1);
|
||||
|
||||
std::vector<std::string> without_neighbors;
|
||||
lua_getfield(L, abm_index, "without_neighbors");
|
||||
read_nodenames(L, -1, without_neighbors);
|
||||
lua_pop(L, 1);
|
||||
|
||||
float trigger_interval = 10.0;
|
||||
getfloatfield(L, abm_index, "interval", trigger_interval);
|
||||
|
||||
int trigger_chance = 50;
|
||||
getintfield(L, abm_index, "chance", trigger_chance);
|
||||
|
||||
bool simple_catch_up = true;
|
||||
getboolfield(L, abm_index, "catch_up", simple_catch_up);
|
||||
|
||||
s16 min_y = INT16_MIN;
|
||||
getintfield(L, abm_index, "min_y", min_y);
|
||||
|
||||
s16 max_y = INT16_MAX;
|
||||
getintfield(L, abm_index, "max_y", max_y);
|
||||
|
||||
lua_getfield(L, abm_index, "action");
|
||||
luaL_checktype(L, abm_index + 1, LUA_TFUNCTION);
|
||||
lua_pop(L, 1);
|
||||
|
||||
return new LuaABM(id, name, trigger_contents, required_neighbors,
|
||||
without_neighbors, trigger_interval, trigger_chance,
|
||||
simple_catch_up, min_y, max_y);
|
||||
}
|
||||
|
||||
void ScriptApiEnv::readABMs()
|
||||
{
|
||||
SCRIPTAPI_PRECHECKHEADER
|
||||
|
@ -212,45 +274,10 @@ void ScriptApiEnv::readABMs()
|
|||
int id = lua_tonumber(L, -2);
|
||||
int current_abm = lua_gettop(L);
|
||||
|
||||
std::vector<std::string> trigger_contents;
|
||||
lua_getfield(L, current_abm, "nodenames");
|
||||
read_nodenames(L, -1, trigger_contents);
|
||||
lua_pop(L, 1);
|
||||
|
||||
std::vector<std::string> required_neighbors;
|
||||
lua_getfield(L, current_abm, "neighbors");
|
||||
read_nodenames(L, -1, required_neighbors);
|
||||
lua_pop(L, 1);
|
||||
|
||||
std::vector<std::string> without_neighbors;
|
||||
lua_getfield(L, current_abm, "without_neighbors");
|
||||
read_nodenames(L, -1, without_neighbors);
|
||||
lua_pop(L, 1);
|
||||
|
||||
float trigger_interval = 10.0;
|
||||
getfloatfield(L, current_abm, "interval", trigger_interval);
|
||||
|
||||
int trigger_chance = 50;
|
||||
getintfield(L, current_abm, "chance", trigger_chance);
|
||||
|
||||
bool simple_catch_up = true;
|
||||
getboolfield(L, current_abm, "catch_up", simple_catch_up);
|
||||
|
||||
s16 min_y = INT16_MIN;
|
||||
getintfield(L, current_abm, "min_y", min_y);
|
||||
|
||||
s16 max_y = INT16_MAX;
|
||||
getintfield(L, current_abm, "max_y", max_y);
|
||||
|
||||
lua_getfield(L, current_abm, "action");
|
||||
luaL_checktype(L, current_abm + 1, LUA_TFUNCTION);
|
||||
lua_pop(L, 1);
|
||||
|
||||
LuaABM *abm = new LuaABM(id, trigger_contents, required_neighbors,
|
||||
without_neighbors, trigger_interval, trigger_chance,
|
||||
simple_catch_up, min_y, max_y);
|
||||
|
||||
LuaABM *abm = readABM(L, current_abm, id);
|
||||
if (abm != nullptr) {
|
||||
env->addActiveBlockModifier(abm);
|
||||
}
|
||||
|
||||
// removes value, keeps key for next iteration
|
||||
lua_pop(L, 1);
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
#include "cpp_api/s_base.h"
|
||||
#include "irr_v3d.h"
|
||||
#include "mapnode.h"
|
||||
#include "server/blockmodifier.h"
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
class ServerEnvironment;
|
||||
class MapBlock;
|
||||
class LuaABM;
|
||||
struct ScriptCallbackState;
|
||||
|
||||
class ScriptApiEnv : virtual public ScriptApiBase
|
||||
|
@ -50,7 +52,10 @@ public:
|
|||
void triggerLBM(int id, MapBlock *block,
|
||||
const std::unordered_set<v3s16> &positions, float dtime_s);
|
||||
|
||||
static int override_abm(lua_State * L, ServerEnvironment *env);
|
||||
private:
|
||||
static LuaABM *readABM(lua_State *L, int abm_index, int id);
|
||||
|
||||
void readABMs();
|
||||
|
||||
void readLBMs();
|
||||
|
|
|
@ -1383,6 +1383,15 @@ int ModApiEnv::l_get_translated_string(lua_State * L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
// override_abm(abm_name, parameters)
|
||||
int ModApiEnv::l_override_abm(lua_State *L)
|
||||
{
|
||||
GET_ENV_PTR;
|
||||
|
||||
// redirect to s_env.cpp to avoid need of public LuaABM definiton or reinterpret_cast
|
||||
return ScriptApiEnv::override_abm(L, env);
|
||||
}
|
||||
|
||||
void ModApiEnv::Initialize(lua_State *L, int top)
|
||||
{
|
||||
API_FCT(set_node);
|
||||
|
@ -1435,6 +1444,7 @@ void ModApiEnv::Initialize(lua_State *L, int top)
|
|||
API_FCT(forceload_free_block);
|
||||
API_FCT(compare_block_status);
|
||||
API_FCT(get_translated_string);
|
||||
API_FCT(override_abm);
|
||||
}
|
||||
|
||||
void ModApiEnv::InitializeClient(lua_State *L, int top)
|
||||
|
|
|
@ -225,6 +225,9 @@ private:
|
|||
// get_translated_string(lang_code, string)
|
||||
static int l_get_translated_string(lua_State * L);
|
||||
|
||||
// override_abm(abm_name, new_data)
|
||||
static int l_override_abm(lua_State * L);
|
||||
|
||||
public:
|
||||
static void Initialize(lua_State *L, int top);
|
||||
static void InitializeClient(lua_State *L, int top);
|
||||
|
|
|
@ -47,19 +47,19 @@ ABMHandler::ABMHandler(std::vector<ABMWithState> &abms,
|
|||
for (ABMWithState &abmws : abms) {
|
||||
ActiveBlockModifier *abm = abmws.abm;
|
||||
float trigger_interval = abm->getTriggerInterval();
|
||||
if (trigger_interval < 0.001f)
|
||||
if( trigger_interval < 0.001f)
|
||||
trigger_interval = 0.001f;
|
||||
float actual_interval = dtime_s;
|
||||
if (use_timers) {
|
||||
abmws.timer += dtime_s;
|
||||
if (abmws.timer < trigger_interval)
|
||||
continue;
|
||||
abmws.timer -= trigger_interval;
|
||||
abmws.timer = std::fmod(abmws.timer, trigger_interval);
|
||||
actual_interval = trigger_interval;
|
||||
}
|
||||
float chance = abm->getTriggerChance();
|
||||
if (chance == 0)
|
||||
chance = 1;
|
||||
continue;
|
||||
|
||||
ActiveABM aabm;
|
||||
aabm.abm = abm;
|
||||
|
|
|
@ -28,6 +28,8 @@ public:
|
|||
ActiveBlockModifier() = default;
|
||||
virtual ~ActiveBlockModifier() = default;
|
||||
|
||||
// Optional name of modifier.
|
||||
virtual const std::string &getName() const = 0;
|
||||
// Set of contents to trigger on
|
||||
virtual const std::vector<std::string> &getTriggerContents() const = 0;
|
||||
// Set of required neighbors (trigger doesn't happen if none are found)
|
||||
|
|
|
@ -582,6 +582,19 @@ void ServerEnvironment::addActiveBlockModifier(ActiveBlockModifier *abm)
|
|||
m_abms.emplace_back(abm);
|
||||
}
|
||||
|
||||
bool ServerEnvironment::replaceActiveBlockModifier(ActiveBlockModifier *abm)
|
||||
{
|
||||
std::string name(abm->getName());
|
||||
for (auto &&m_abm : m_abms) {
|
||||
if (m_abm.abm->getName() == name) {
|
||||
delete m_abm.abm;
|
||||
m_abm = abm;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ServerEnvironment::addLoadingBlockModifierDef(LoadingBlockModifierDef *lbm)
|
||||
{
|
||||
m_lbm_mgr.addLBMDef(lbm);
|
||||
|
|
|
@ -205,6 +205,7 @@ public:
|
|||
*/
|
||||
|
||||
void addActiveBlockModifier(ActiveBlockModifier *abm);
|
||||
bool replaceActiveBlockModifier(ActiveBlockModifier *abm);
|
||||
void addLoadingBlockModifierDef(LoadingBlockModifierDef *lbm);
|
||||
|
||||
/*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue