mirror of
https://github.com/minetest/minetest.git
synced 2025-02-17 10:23:47 +01:00
Add callback on_mapblocks_changed
This commit is contained in:
@ -8,10 +8,9 @@
|
|||||||
-- Misc. API functions
|
-- Misc. API functions
|
||||||
--
|
--
|
||||||
|
|
||||||
|
-- This must match the implementation in src/script/common/c_converter.h
|
||||||
function core.hash_node_position(pos)
|
function core.hash_node_position(pos)
|
||||||
return (pos.z + 32768) * 65536 * 65536
|
return (pos.z + 0x8000) * 0x100000000 + (pos.y + 0x8000) * 0x10000 + (pos.x + 0x8000)
|
||||||
+ (pos.y + 32768) * 65536
|
|
||||||
+ pos.x + 32768
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -633,6 +633,17 @@ core.registered_on_player_inventory_actions, core.register_on_player_inventory_a
|
|||||||
core.registered_allow_player_inventory_actions, core.register_allow_player_inventory_action = make_registration()
|
core.registered_allow_player_inventory_actions, core.register_allow_player_inventory_action = make_registration()
|
||||||
core.registered_on_rightclickplayers, core.register_on_rightclickplayer = make_registration()
|
core.registered_on_rightclickplayers, core.register_on_rightclickplayer = make_registration()
|
||||||
core.registered_on_liquid_transformed, core.register_on_liquid_transformed = make_registration()
|
core.registered_on_liquid_transformed, core.register_on_liquid_transformed = make_registration()
|
||||||
|
core.registered_on_mapblocks_changed, core.register_on_mapblocks_changed = make_registration()
|
||||||
|
|
||||||
|
core.register_on_mods_loaded(function()
|
||||||
|
core.after(0, function()
|
||||||
|
setmetatable(core.registered_on_mapblocks_changed, {
|
||||||
|
__newindex = function()
|
||||||
|
error("on_mapblocks_changed callbacks must be registered at load time")
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Compatibility for on_mapgen_init()
|
-- Compatibility for on_mapgen_init()
|
||||||
|
@ -43,6 +43,7 @@ local register_functions = {
|
|||||||
register_on_item_eat = 0,
|
register_on_item_eat = 0,
|
||||||
register_on_punchplayer = 0,
|
register_on_punchplayer = 0,
|
||||||
register_on_player_hpchange = 0,
|
register_on_player_hpchange = 0,
|
||||||
|
register_on_mapblocks_changed = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -5372,6 +5372,16 @@ Call these functions only at load time!
|
|||||||
* `pos_list` is an array of all modified positions.
|
* `pos_list` is an array of all modified positions.
|
||||||
* `node_list` is an array of the old node that was previously at the position
|
* `node_list` is an array of the old node that was previously at the position
|
||||||
with the corresponding index in pos_list.
|
with the corresponding index in pos_list.
|
||||||
|
* `minetest.register_on_mapblocks_changed(function(modified_blocks, modified_block_count))`
|
||||||
|
* Called soon after any nodes or node metadata have been modified. No
|
||||||
|
modifications will be missed, but there may be false positives.
|
||||||
|
* Will never be called more than once per server step.
|
||||||
|
* `modified_blocks` is the set of modified mapblock position hashes. These
|
||||||
|
are in the same format as those produced by `minetest.hash_node_position`,
|
||||||
|
and can be converted to positions with `minetest.get_position_from_hash`.
|
||||||
|
The set is a table where the keys are hashes and the values are `true`.
|
||||||
|
* `modified_block_count` is the number of entries in the set.
|
||||||
|
* Note: callbacks must be registered at mod load time.
|
||||||
|
|
||||||
Setting-related
|
Setting-related
|
||||||
---------------
|
---------------
|
||||||
|
@ -147,3 +147,33 @@ local function test_mapgen_edges(cb)
|
|||||||
minetest.emerge_area(max_edge, max_edge:add(1), emerge_block, max_finished)
|
minetest.emerge_area(max_edge, max_edge:add(1), emerge_block, max_finished)
|
||||||
end
|
end
|
||||||
unittests.register("test_mapgen_edges", test_mapgen_edges, {map=true, async=true})
|
unittests.register("test_mapgen_edges", test_mapgen_edges, {map=true, async=true})
|
||||||
|
|
||||||
|
local finish_test_on_mapblocks_changed
|
||||||
|
minetest.register_on_mapblocks_changed(function(modified_blocks, modified_block_count)
|
||||||
|
if finish_test_on_mapblocks_changed then
|
||||||
|
finish_test_on_mapblocks_changed(modified_blocks, modified_block_count)
|
||||||
|
finish_test_on_mapblocks_changed = nil
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
local function test_on_mapblocks_changed(cb, player, pos)
|
||||||
|
local bp1 = (pos / minetest.MAP_BLOCKSIZE):floor()
|
||||||
|
local bp2 = bp1:add(1)
|
||||||
|
for _, bp in ipairs({bp1, bp2}) do
|
||||||
|
-- Make a modification in the block.
|
||||||
|
local p = bp * minetest.MAP_BLOCKSIZE
|
||||||
|
minetest.load_area(p)
|
||||||
|
local meta = minetest.get_meta(p)
|
||||||
|
meta:set_int("test_on_mapblocks_changed", meta:get_int("test_on_mapblocks_changed") + 1)
|
||||||
|
end
|
||||||
|
finish_test_on_mapblocks_changed = function(modified_blocks, modified_block_count)
|
||||||
|
if modified_block_count < 2 then
|
||||||
|
return cb("Expected at least two mapblocks to be recorded as modified")
|
||||||
|
end
|
||||||
|
if not modified_blocks[minetest.hash_node_position(bp1)] or
|
||||||
|
not modified_blocks[minetest.hash_node_position(bp2)] then
|
||||||
|
return cb("The expected mapblocks were not recorded as modified")
|
||||||
|
end
|
||||||
|
cb()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
unittests.register("test_on_mapblocks_changed", test_on_mapblocks_changed, {map=true, async=true})
|
||||||
|
@ -121,3 +121,12 @@ void warn_if_field_exists(lua_State *L, int table,
|
|||||||
|
|
||||||
size_t write_array_slice_float(lua_State *L, int table_index, float *data,
|
size_t write_array_slice_float(lua_State *L, int table_index, float *data,
|
||||||
v3u16 data_size, v3u16 slice_offset, v3u16 slice_size);
|
v3u16 data_size, v3u16 slice_offset, v3u16 slice_size);
|
||||||
|
|
||||||
|
// This must match the implementation in builtin/game/misc_s.lua
|
||||||
|
// Note that this returns a floating point result as Lua integers are 32-bit
|
||||||
|
inline lua_Number hash_node_position(v3s16 pos)
|
||||||
|
{
|
||||||
|
return (((s64)pos.Z + 0x8000L) << 32)
|
||||||
|
| (((s64)pos.Y + 0x8000L) << 16)
|
||||||
|
| ((s64)pos.X + 0x8000L);
|
||||||
|
}
|
||||||
|
@ -299,3 +299,36 @@ void ScriptApiEnv::on_liquid_transformed(
|
|||||||
|
|
||||||
runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
|
runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptApiEnv::on_mapblocks_changed(const std::unordered_set<v3s16> &set)
|
||||||
|
{
|
||||||
|
SCRIPTAPI_PRECHECKHEADER
|
||||||
|
|
||||||
|
// Get core.registered_on_mapblocks_changed
|
||||||
|
lua_getglobal(L, "core");
|
||||||
|
lua_getfield(L, -1, "registered_on_mapblocks_changed");
|
||||||
|
luaL_checktype(L, -1, LUA_TTABLE);
|
||||||
|
lua_remove(L, -2);
|
||||||
|
|
||||||
|
// Convert the set to a set of position hashes
|
||||||
|
lua_createtable(L, 0, set.size());
|
||||||
|
for(const v3s16 &p : set) {
|
||||||
|
lua_pushnumber(L, hash_node_position(p));
|
||||||
|
lua_pushboolean(L, true);
|
||||||
|
lua_rawset(L, -3);
|
||||||
|
}
|
||||||
|
lua_pushinteger(L, set.size());
|
||||||
|
|
||||||
|
runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScriptApiEnv::has_on_mapblocks_changed()
|
||||||
|
{
|
||||||
|
SCRIPTAPI_PRECHECKHEADER
|
||||||
|
|
||||||
|
// Get core.registered_on_mapblocks_changed
|
||||||
|
lua_getglobal(L, "core");
|
||||||
|
lua_getfield(L, -1, "registered_on_mapblocks_changed");
|
||||||
|
luaL_checktype(L, -1, LUA_TTABLE);
|
||||||
|
return lua_objlen(L, -1) > 0;
|
||||||
|
}
|
||||||
|
@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "cpp_api/s_base.h"
|
#include "cpp_api/s_base.h"
|
||||||
#include "irr_v3d.h"
|
#include "irr_v3d.h"
|
||||||
#include "mapnode.h"
|
#include "mapnode.h"
|
||||||
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class ServerEnvironment;
|
class ServerEnvironment;
|
||||||
@ -48,5 +49,11 @@ public:
|
|||||||
// Called after liquid transform changes
|
// Called after liquid transform changes
|
||||||
void on_liquid_transformed(const std::vector<std::pair<v3s16, MapNode>> &list);
|
void on_liquid_transformed(const std::vector<std::pair<v3s16, MapNode>> &list);
|
||||||
|
|
||||||
|
// Called after mapblock changes
|
||||||
|
void on_mapblocks_changed(const std::unordered_set<v3s16> &set);
|
||||||
|
|
||||||
|
// Determines whether there are any on_mapblocks_changed callbacks
|
||||||
|
bool has_on_mapblocks_changed();
|
||||||
|
|
||||||
void initializeEnvironment(ServerEnvironment *env);
|
void initializeEnvironment(ServerEnvironment *env);
|
||||||
};
|
};
|
||||||
|
@ -381,6 +381,18 @@ void ActiveBlockList::update(std::vector<PlayerSAO*> &active_players,
|
|||||||
m_list = std::move(newlist);
|
m_list = std::move(newlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
OnMapblocksChangedReceiver
|
||||||
|
*/
|
||||||
|
|
||||||
|
void OnMapblocksChangedReceiver::onMapEditEvent(const MapEditEvent &event)
|
||||||
|
{
|
||||||
|
assert(receiving);
|
||||||
|
for (const v3s16 &p : event.modified_blocks) {
|
||||||
|
modified_blocks.insert(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ServerEnvironment
|
ServerEnvironment
|
||||||
*/
|
*/
|
||||||
@ -476,6 +488,11 @@ void ServerEnvironment::init()
|
|||||||
|
|
||||||
m_player_database = openPlayerDatabase(player_backend_name, m_path_world, conf);
|
m_player_database = openPlayerDatabase(player_backend_name, m_path_world, conf);
|
||||||
m_auth_database = openAuthDatabase(auth_backend_name, m_path_world, conf);
|
m_auth_database = openAuthDatabase(auth_backend_name, m_path_world, conf);
|
||||||
|
|
||||||
|
if (m_map && m_script->has_on_mapblocks_changed()) {
|
||||||
|
m_map->addEventReceiver(&m_on_mapblocks_changed_receiver);
|
||||||
|
m_on_mapblocks_changed_receiver.receiving = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerEnvironment::~ServerEnvironment()
|
ServerEnvironment::~ServerEnvironment()
|
||||||
@ -1570,6 +1587,14 @@ void ServerEnvironment::step(float dtime)
|
|||||||
// Send outdated detached inventories
|
// Send outdated detached inventories
|
||||||
m_server->sendDetachedInventories(PEER_ID_INEXISTENT, true);
|
m_server->sendDetachedInventories(PEER_ID_INEXISTENT, true);
|
||||||
|
|
||||||
|
// Notify mods of modified mapblocks
|
||||||
|
if (m_on_mapblocks_changed_receiver.receiving &&
|
||||||
|
!m_on_mapblocks_changed_receiver.modified_blocks.empty()) {
|
||||||
|
std::unordered_set<v3s16> modified_blocks;
|
||||||
|
std::swap(modified_blocks, m_on_mapblocks_changed_receiver.modified_blocks);
|
||||||
|
m_script->on_mapblocks_changed(modified_blocks);
|
||||||
|
}
|
||||||
|
|
||||||
const auto end_time = porting::getTimeUs();
|
const auto end_time = porting::getTimeUs();
|
||||||
m_step_time_counter->increment(end_time - start_time);
|
m_step_time_counter->increment(end_time - start_time);
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include "activeobject.h"
|
#include "activeobject.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
#include "mapnode.h"
|
#include "map.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "server/activeobjectmgr.h"
|
#include "server/activeobjectmgr.h"
|
||||||
#include "util/numeric.h"
|
#include "util/numeric.h"
|
||||||
@ -30,9 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
class IGameDef;
|
class IGameDef;
|
||||||
class ServerMap;
|
|
||||||
struct GameParams;
|
struct GameParams;
|
||||||
class MapBlock;
|
|
||||||
class RemotePlayer;
|
class RemotePlayer;
|
||||||
class PlayerDatabase;
|
class PlayerDatabase;
|
||||||
class AuthDatabase;
|
class AuthDatabase;
|
||||||
@ -193,6 +191,16 @@ public:
|
|||||||
std::set<v3s16> m_forceloaded_list;
|
std::set<v3s16> m_forceloaded_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
ServerEnvironment::m_on_mapblocks_changed_receiver
|
||||||
|
*/
|
||||||
|
struct OnMapblocksChangedReceiver : public MapEventReceiver {
|
||||||
|
std::unordered_set<v3s16> modified_blocks;
|
||||||
|
bool receiving = false;
|
||||||
|
|
||||||
|
void onMapEditEvent(const MapEditEvent &event) override;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Operation mode for ServerEnvironment::clearObjects()
|
Operation mode for ServerEnvironment::clearObjects()
|
||||||
*/
|
*/
|
||||||
@ -455,6 +463,8 @@ private:
|
|||||||
Server *m_server;
|
Server *m_server;
|
||||||
// Active Object Manager
|
// Active Object Manager
|
||||||
server::ActiveObjectMgr m_ao_manager;
|
server::ActiveObjectMgr m_ao_manager;
|
||||||
|
// on_mapblocks_changed map event receiver
|
||||||
|
OnMapblocksChangedReceiver m_on_mapblocks_changed_receiver;
|
||||||
// World path
|
// World path
|
||||||
const std::string m_path_world;
|
const std::string m_path_world;
|
||||||
// Outgoing network message buffer for active objects
|
// Outgoing network message buffer for active objects
|
||||||
|
Reference in New Issue
Block a user