mirror of
https://github.com/minetest/minetest.git
synced 2024-11-27 01:53:45 +01:00
Add on_deactivate callback for luaentities (#10723)
This commit is contained in:
parent
ad58fb2206
commit
dd5a732fa9
@ -160,6 +160,7 @@ local function init()
|
|||||||
-- Simple iteration would ignore lookup via __index.
|
-- Simple iteration would ignore lookup via __index.
|
||||||
local entity_instrumentation = {
|
local entity_instrumentation = {
|
||||||
"on_activate",
|
"on_activate",
|
||||||
|
"on_deactivate",
|
||||||
"on_step",
|
"on_step",
|
||||||
"on_punch",
|
"on_punch",
|
||||||
"on_rightclick",
|
"on_rightclick",
|
||||||
|
@ -4207,6 +4207,8 @@ Callbacks:
|
|||||||
* Called when the object is instantiated.
|
* Called when the object is instantiated.
|
||||||
* `dtime_s` is the time passed since the object was unloaded, which can be
|
* `dtime_s` is the time passed since the object was unloaded, which can be
|
||||||
used for updating the entity state.
|
used for updating the entity state.
|
||||||
|
* `on_deactivate(self)
|
||||||
|
* Called when the object is about to get removed or unloaded.
|
||||||
* `on_step(self, dtime)`
|
* `on_step(self, dtime)`
|
||||||
* Called on every server tick, after movement and collision processing.
|
* Called on every server tick, after movement and collision processing.
|
||||||
`dtime` is usually 0.1 seconds, as per the `dedicated_server_step` setting
|
`dtime` is usually 0.1 seconds, as per the `dedicated_server_step` setting
|
||||||
|
@ -31,6 +31,9 @@ minetest.register_entity("testentities:callback", {
|
|||||||
on_activate = function(self, staticdata, dtime_s)
|
on_activate = function(self, staticdata, dtime_s)
|
||||||
message("Callback entity: on_activate! pos="..spos(self).."; dtime_s="..dtime_s)
|
message("Callback entity: on_activate! pos="..spos(self).."; dtime_s="..dtime_s)
|
||||||
end,
|
end,
|
||||||
|
on_deactivate = function(self)
|
||||||
|
message("Callback entity: on_deactivate! pos="..spos(self))
|
||||||
|
end,
|
||||||
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
|
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
|
||||||
local name = get_object_name(puncher)
|
local name = get_object_name(puncher)
|
||||||
message(
|
message(
|
||||||
|
@ -103,6 +103,32 @@ void ScriptApiEntity::luaentity_Activate(u16 id,
|
|||||||
lua_pop(L, 2); // Pop object and error handler
|
lua_pop(L, 2); // Pop object and error handler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScriptApiEntity::luaentity_Deactivate(u16 id)
|
||||||
|
{
|
||||||
|
SCRIPTAPI_PRECHECKHEADER
|
||||||
|
|
||||||
|
verbosestream << "scriptapi_luaentity_deactivate: id=" << id << std::endl;
|
||||||
|
|
||||||
|
int error_handler = PUSH_ERROR_HANDLER(L);
|
||||||
|
|
||||||
|
// Get the entity
|
||||||
|
luaentity_get(L, id);
|
||||||
|
int object = lua_gettop(L);
|
||||||
|
|
||||||
|
// Get on_deactivate
|
||||||
|
lua_getfield(L, -1, "on_deactivate");
|
||||||
|
if (!lua_isnil(L, -1)) {
|
||||||
|
luaL_checktype(L, -1, LUA_TFUNCTION);
|
||||||
|
lua_pushvalue(L, object);
|
||||||
|
|
||||||
|
setOriginFromTable(object);
|
||||||
|
PCALL_RES(lua_pcall(L, 1, 0, error_handler));
|
||||||
|
} else {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
lua_pop(L, 2); // Pop object and error handler
|
||||||
|
}
|
||||||
|
|
||||||
void ScriptApiEntity::luaentity_Remove(u16 id)
|
void ScriptApiEntity::luaentity_Remove(u16 id)
|
||||||
{
|
{
|
||||||
SCRIPTAPI_PRECHECKHEADER
|
SCRIPTAPI_PRECHECKHEADER
|
||||||
|
@ -33,6 +33,7 @@ public:
|
|||||||
bool luaentity_Add(u16 id, const char *name);
|
bool luaentity_Add(u16 id, const char *name);
|
||||||
void luaentity_Activate(u16 id,
|
void luaentity_Activate(u16 id,
|
||||||
const std::string &staticdata, u32 dtime_s);
|
const std::string &staticdata, u32 dtime_s);
|
||||||
|
void luaentity_Deactivate(u16 id);
|
||||||
void luaentity_Remove(u16 id);
|
void luaentity_Remove(u16 id);
|
||||||
std::string luaentity_GetStaticdata(u16 id);
|
std::string luaentity_GetStaticdata(u16 id);
|
||||||
void luaentity_GetProperties(u16 id,
|
void luaentity_GetProperties(u16 id,
|
||||||
|
@ -110,7 +110,7 @@ int ObjectRef::l_remove(lua_State *L)
|
|||||||
sao->clearParentAttachment();
|
sao->clearParentAttachment();
|
||||||
|
|
||||||
verbosestream << "ObjectRef::l_remove(): id=" << sao->getId() << std::endl;
|
verbosestream << "ObjectRef::l_remove(): id=" << sao->getId() << std::endl;
|
||||||
sao->m_pending_removal = true;
|
sao->markForRemoval();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +112,15 @@ void LuaEntitySAO::addedToEnvironment(u32 dtime_s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LuaEntitySAO::dispatchScriptDeactivate()
|
||||||
|
{
|
||||||
|
// Ensure that this is in fact a registered entity,
|
||||||
|
// and that it isn't already gone.
|
||||||
|
// The latter also prevents this from ever being called twice.
|
||||||
|
if (m_registered && !isGone())
|
||||||
|
m_env->getScriptIface()->luaentity_Deactivate(m_id);
|
||||||
|
}
|
||||||
|
|
||||||
void LuaEntitySAO::step(float dtime, bool send_recommended)
|
void LuaEntitySAO::step(float dtime, bool send_recommended)
|
||||||
{
|
{
|
||||||
if(!m_properties_sent)
|
if(!m_properties_sent)
|
||||||
@ -302,7 +311,7 @@ u16 LuaEntitySAO::punch(v3f dir,
|
|||||||
{
|
{
|
||||||
if (!m_registered) {
|
if (!m_registered) {
|
||||||
// Delete unknown LuaEntities when punched
|
// Delete unknown LuaEntities when punched
|
||||||
m_pending_removal = true;
|
markForRemoval();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,7 +344,7 @@ u16 LuaEntitySAO::punch(v3f dir,
|
|||||||
clearParentAttachment();
|
clearParentAttachment();
|
||||||
clearChildAttachments();
|
clearChildAttachments();
|
||||||
m_env->getScriptIface()->luaentity_on_death(m_id, puncher);
|
m_env->getScriptIface()->luaentity_on_death(m_id, puncher);
|
||||||
m_pending_removal = true;
|
markForRemoval();
|
||||||
}
|
}
|
||||||
|
|
||||||
actionstream << puncher->getDescription() << " (id=" << puncher->getId() <<
|
actionstream << puncher->getDescription() << " (id=" << puncher->getId() <<
|
||||||
|
@ -71,6 +71,11 @@ public:
|
|||||||
bool getSelectionBox(aabb3f *toset) const;
|
bool getSelectionBox(aabb3f *toset) const;
|
||||||
bool collideWithObjects() const;
|
bool collideWithObjects() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void dispatchScriptDeactivate();
|
||||||
|
virtual void onMarkedForDeactivation() { dispatchScriptDeactivate(); }
|
||||||
|
virtual void onMarkedForRemoval() { dispatchScriptDeactivate(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string getPropertyPacket();
|
std::string getPropertyPacket();
|
||||||
void sendPosition(bool do_interpolate, bool is_movement_end);
|
void sendPosition(bool do_interpolate, bool is_movement_end);
|
||||||
|
@ -531,7 +531,7 @@ bool PlayerSAO::setWieldedItem(const ItemStack &item)
|
|||||||
void PlayerSAO::disconnected()
|
void PlayerSAO::disconnected()
|
||||||
{
|
{
|
||||||
m_peer_id = PEER_ID_INEXISTENT;
|
m_peer_id = PEER_ID_INEXISTENT;
|
||||||
m_pending_removal = true;
|
markForRemoval();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerSAO::unlinkPlayerSessionAndSave()
|
void PlayerSAO::unlinkPlayerSessionAndSave()
|
||||||
|
@ -73,3 +73,19 @@ void ServerActiveObject::dumpAOMessagesToQueue(std::queue<ActiveObjectMessage> &
|
|||||||
m_messages_out.pop();
|
m_messages_out.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ServerActiveObject::markForRemoval()
|
||||||
|
{
|
||||||
|
if (!m_pending_removal) {
|
||||||
|
onMarkedForRemoval();
|
||||||
|
m_pending_removal = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerActiveObject::markForDeactivation()
|
||||||
|
{
|
||||||
|
if (!m_pending_deactivation) {
|
||||||
|
onMarkedForDeactivation();
|
||||||
|
m_pending_deactivation = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -70,6 +70,10 @@ public:
|
|||||||
virtual bool environmentDeletes() const
|
virtual bool environmentDeletes() const
|
||||||
{ return true; }
|
{ return true; }
|
||||||
|
|
||||||
|
// Safely mark the object for removal or deactivation
|
||||||
|
void markForRemoval();
|
||||||
|
void markForDeactivation();
|
||||||
|
|
||||||
// Create a certain type of ServerActiveObject
|
// Create a certain type of ServerActiveObject
|
||||||
static ServerActiveObject* create(ActiveObjectType type,
|
static ServerActiveObject* create(ActiveObjectType type,
|
||||||
ServerEnvironment *env, u16 id, v3f pos,
|
ServerEnvironment *env, u16 id, v3f pos,
|
||||||
@ -213,25 +217,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
u16 m_known_by_count = 0;
|
u16 m_known_by_count = 0;
|
||||||
|
|
||||||
/*
|
|
||||||
- Whether this object is to be removed when nobody knows about
|
|
||||||
it anymore.
|
|
||||||
- Removal is delayed to preserve the id for the time during which
|
|
||||||
it could be confused to some other object by some client.
|
|
||||||
- This is usually set to true by the step() method when the object wants
|
|
||||||
to be deleted but can be set by anything else too.
|
|
||||||
*/
|
|
||||||
bool m_pending_removal = false;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Same purpose as m_pending_removal but for deactivation.
|
|
||||||
deactvation = save static data in block, remove active object
|
|
||||||
|
|
||||||
If this is set alongside with m_pending_removal, removal takes
|
|
||||||
priority.
|
|
||||||
*/
|
|
||||||
bool m_pending_deactivation = false;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A getter that unifies the above to answer the question:
|
A getter that unifies the above to answer the question:
|
||||||
"Can the environment still interact with this object?"
|
"Can the environment still interact with this object?"
|
||||||
@ -239,6 +224,9 @@ public:
|
|||||||
inline bool isGone() const
|
inline bool isGone() const
|
||||||
{ return m_pending_removal || m_pending_deactivation; }
|
{ return m_pending_removal || m_pending_deactivation; }
|
||||||
|
|
||||||
|
inline bool isPendingRemoval() const
|
||||||
|
{ return m_pending_removal; }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Whether the object's static data has been stored to a block
|
Whether the object's static data has been stored to a block
|
||||||
*/
|
*/
|
||||||
@ -250,6 +238,9 @@ public:
|
|||||||
v3s16 m_static_block = v3s16(1337,1337,1337);
|
v3s16 m_static_block = v3s16(1337,1337,1337);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual void onMarkedForDeactivation() {}
|
||||||
|
virtual void onMarkedForRemoval() {}
|
||||||
|
|
||||||
virtual void onAttach(int parent_id) {}
|
virtual void onAttach(int parent_id) {}
|
||||||
virtual void onDetach(int parent_id) {}
|
virtual void onDetach(int parent_id) {}
|
||||||
|
|
||||||
@ -257,6 +248,27 @@ protected:
|
|||||||
v3f m_base_position;
|
v3f m_base_position;
|
||||||
std::unordered_set<u32> m_attached_particle_spawners;
|
std::unordered_set<u32> m_attached_particle_spawners;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Same purpose as m_pending_removal but for deactivation.
|
||||||
|
deactvation = save static data in block, remove active object
|
||||||
|
|
||||||
|
If this is set alongside with m_pending_removal, removal takes
|
||||||
|
priority.
|
||||||
|
Note: Do not assign this directly, use markForDeactivation() instead.
|
||||||
|
*/
|
||||||
|
bool m_pending_deactivation = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
- Whether this object is to be removed when nobody knows about
|
||||||
|
it anymore.
|
||||||
|
- Removal is delayed to preserve the id for the time during which
|
||||||
|
it could be confused to some other object by some client.
|
||||||
|
- This is usually set to true by the step() method when the object wants
|
||||||
|
to be deleted but can be set by anything else too.
|
||||||
|
Note: Do not assign this directly, use markForRemoval() instead.
|
||||||
|
*/
|
||||||
|
bool m_pending_removal = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Queue of messages to be sent to the client
|
Queue of messages to be sent to the client
|
||||||
*/
|
*/
|
||||||
|
@ -1164,7 +1164,7 @@ void ServerEnvironment::clearObjects(ClearObjectsMode mode)
|
|||||||
|
|
||||||
// If known by some client, don't delete immediately
|
// 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_removal = true;
|
obj->markForRemoval();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1792,7 +1792,7 @@ void ServerEnvironment::removeRemovedObjects()
|
|||||||
/*
|
/*
|
||||||
Delete static data from block if removed
|
Delete static data from block if removed
|
||||||
*/
|
*/
|
||||||
if (obj->m_pending_removal)
|
if (obj->isPendingRemoval())
|
||||||
deleteStaticFromBlock(obj, id, MOD_REASON_REMOVE_OBJECTS_REMOVE, false);
|
deleteStaticFromBlock(obj, id, MOD_REASON_REMOVE_OBJECTS_REMOVE, false);
|
||||||
|
|
||||||
// If still known by clients, don't actually remove. On some future
|
// If still known by clients, don't actually remove. On some future
|
||||||
@ -1803,7 +1803,7 @@ void ServerEnvironment::removeRemovedObjects()
|
|||||||
/*
|
/*
|
||||||
Move static data from active to stored if deactivated
|
Move static data from active to stored if deactivated
|
||||||
*/
|
*/
|
||||||
if (!obj->m_pending_removal && obj->m_static_exists) {
|
if (!obj->isPendingRemoval() && obj->m_static_exists) {
|
||||||
MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
|
MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
|
||||||
if (block) {
|
if (block) {
|
||||||
const auto i = block->m_static_objects.m_active.find(id);
|
const auto i = block->m_static_objects.m_active.find(id);
|
||||||
@ -1991,6 +1991,7 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
|
|||||||
if (!force_delete && obj->m_static_exists &&
|
if (!force_delete && obj->m_static_exists &&
|
||||||
!m_active_blocks.contains(obj->m_static_block) &&
|
!m_active_blocks.contains(obj->m_static_block) &&
|
||||||
m_active_blocks.contains(blockpos_o)) {
|
m_active_blocks.contains(blockpos_o)) {
|
||||||
|
|
||||||
// Delete from block where object was located
|
// Delete from block where object was located
|
||||||
deleteStaticFromBlock(obj, id, MOD_REASON_STATIC_DATA_REMOVED, false);
|
deleteStaticFromBlock(obj, id, MOD_REASON_STATIC_DATA_REMOVED, false);
|
||||||
|
|
||||||
@ -2068,6 +2069,10 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
|
|||||||
force_delete = true;
|
force_delete = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Regardless of what happens to the object at this point, deactivate it first.
|
||||||
|
// This ensures that LuaEntity on_deactivate is always called.
|
||||||
|
obj->markForDeactivation();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If known by some client, set pending deactivation.
|
If known by some client, set pending deactivation.
|
||||||
Otherwise delete it immediately.
|
Otherwise delete it immediately.
|
||||||
@ -2077,7 +2082,6 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
|
|||||||
<< "object id=" << id << " is known by clients"
|
<< "object id=" << id << " is known by clients"
|
||||||
<< "; not deleting yet" << std::endl;
|
<< "; not deleting yet" << std::endl;
|
||||||
|
|
||||||
obj->m_pending_deactivation = true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user