ServerEnv: Clean up object lifecycle handling (#6414)

* ServerEnv: Clean up object lifecycle handling
This commit is contained in:
sfan5 2017-09-15 12:19:01 +02:00 committed by Loïc Blot
parent edbc533414
commit 04839f233f
8 changed files with 175 additions and 213 deletions

View File

@ -59,7 +59,7 @@ public:
m_age += dtime; m_age += dtime;
if(m_age > 10) if(m_age > 10)
{ {
m_removed = true; m_pending_removal = true;
return; return;
} }
@ -397,12 +397,11 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
{ {
ServerMap *map = dynamic_cast<ServerMap *>(&m_env->getMap()); ServerMap *map = dynamic_cast<ServerMap *>(&m_env->getMap());
assert(map); assert(map);
if (!m_pending_deactivation && if (!m_pending_removal &&
map->saoPositionOverLimit(m_base_position)) { map->saoPositionOverLimit(m_base_position)) {
infostream << "Remove SAO " << m_id << "(" << m_init_name infostream << "Removing SAO " << m_id << "(" << m_init_name
<< "), outside of limits" << std::endl; << "), outside of limits" << std::endl;
m_pending_deactivation = true; m_pending_removal = true;
m_removed = true;
return; return;
} }
} }
@ -550,9 +549,9 @@ int LuaEntitySAO::punch(v3f dir,
ServerActiveObject *puncher, ServerActiveObject *puncher,
float time_from_last_punch) float time_from_last_punch)
{ {
if (!m_registered){ if (!m_registered) {
// Delete unknown LuaEntities when punched // Delete unknown LuaEntities when punched
m_removed = true; m_pending_removal = true;
return 0; return 0;
} }
@ -596,12 +595,10 @@ int LuaEntitySAO::punch(v3f dir,
} }
if (getHP() == 0) { if (getHP() == 0) {
m_removed = true; m_pending_removal = true;
m_env->getScriptIface()->luaentity_on_death(m_id, puncher); m_env->getScriptIface()->luaentity_on_death(m_id, puncher);
} }
return result.wear; return result.wear;
} }
@ -1353,11 +1350,10 @@ void PlayerSAO::setWieldIndex(int i)
} }
} }
// Erase the peer id and make the object for removal
void PlayerSAO::disconnected() void PlayerSAO::disconnected()
{ {
m_peer_id = 0; m_peer_id = 0;
m_removed = true; m_pending_removal = true;
} }
void PlayerSAO::unlinkPlayerSessionAndSave() void PlayerSAO::unlinkPlayerSessionAndSave()

View File

@ -1124,8 +1124,8 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
playersao->noCheatDigStart(p_under); playersao->noCheatDigStart(p_under);
} }
else if (pointed.type == POINTEDTHING_OBJECT) { else if (pointed.type == POINTEDTHING_OBJECT) {
// Skip if object has been removed // Skip if object can't be interacted with anymore
if (pointed_object->m_removed) if (pointed_object->isGone())
return; return;
actionstream<<player->getName()<<" punches object " actionstream<<player->getName()<<" punches object "
@ -1283,8 +1283,8 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
if (pointed.type == POINTEDTHING_OBJECT) { if (pointed.type == POINTEDTHING_OBJECT) {
// Right click object // Right click object
// Skip if object has been removed // Skip if object can't be interacted with anymore
if (pointed_object->m_removed) if (pointed_object->isGone())
return; return;
actionstream << player->getName() << " right-clicks object " actionstream << player->getName() << " right-clicks object "

View File

@ -343,6 +343,10 @@ void ScriptApiBase::objectrefGetOrCreate(lua_State *L,
ObjectRef::create(L, cobj); ObjectRef::create(L, cobj);
} else { } else {
push_objectRef(L, cobj->getId()); push_objectRef(L, cobj->getId());
if (cobj->isGone())
warningstream << "ScriptApiBase::objectrefGetOrCreate(): "
<< "Pushing ObjectRef to removed/deactivated object"
<< ", this is probably a bug." << std::endl;
} }
} }

View File

@ -642,7 +642,7 @@ int ModApiEnvMod::l_get_objects_inside_radius(lua_State *L)
std::vector<u16>::const_iterator iter = ids.begin(); std::vector<u16>::const_iterator iter = ids.begin();
for(u32 i = 0; iter != ids.end(); ++iter) { for(u32 i = 0; iter != ids.end(); ++iter) {
ServerActiveObject *obj = env->getActiveObject(*iter); ServerActiveObject *obj = env->getActiveObject(*iter);
if (!obj->m_removed) { if (!obj->isGone()) {
// Insert object reference into table // Insert object reference into table
script->objectrefGetOrCreate(L, obj); script->objectrefGetOrCreate(L, obj);
lua_rawseti(L, -2, ++i); lua_rawseti(L, -2, ++i);

View File

@ -140,15 +140,14 @@ int ObjectRef::l_remove(lua_State *L)
return 0; return 0;
const std::unordered_set<int> &child_ids = co->getAttachmentChildIds(); const std::unordered_set<int> &child_ids = co->getAttachmentChildIds();
std::unordered_set<int>::const_iterator it; for (int child_id : child_ids) {
for (it = child_ids.begin(); it != child_ids.end(); ++it) {
// Child can be NULL if it was deleted earlier // Child can be NULL if it was deleted earlier
if (ServerActiveObject *child = env->getActiveObject(*it)) if (ServerActiveObject *child = env->getActiveObject(child_id))
child->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0)); child->setAttachment(0, "", v3f(0, 0, 0), v3f(0, 0, 0));
} }
verbosestream<<"ObjectRef::l_remove(): id="<<co->getId()<<std::endl; verbosestream << "ObjectRef::l_remove(): id=" << co->getId() << std::endl;
co->m_removed = true; co->m_pending_removal = true;
return 0; return 0;
} }

View File

@ -971,24 +971,17 @@ void ServerEnvironment::clearObjects(ClearObjectsMode mode)
<< "Removing all active objects" << std::endl; << "Removing all active objects" << std::endl;
std::vector<u16> objects_to_remove; std::vector<u16> objects_to_remove;
for (auto &it : m_active_objects) { for (auto &it : m_active_objects) {
u16 id = it.first;
ServerActiveObject* obj = it.second; ServerActiveObject* obj = it.second;
if (obj->getType() == ACTIVEOBJECT_TYPE_PLAYER) if (obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
continue; continue;
u16 id = it.first;
// Delete static object if block is loaded // Delete static object if block is loaded
if (obj->m_static_exists) { deleteStaticFromBlock(obj, id, MOD_REASON_CLEAR_ALL_OBJECTS, true);
MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
if (block) {
block->m_static_objects.remove(id);
block->raiseModified(MOD_STATE_WRITE_NEEDED,
MOD_REASON_CLEAR_ALL_OBJECTS);
obj->m_static_exists = false;
}
}
// 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_deactivation = true; obj->m_pending_removal = true;
obj->m_removed = true;
continue; continue;
} }
@ -1302,16 +1295,14 @@ void ServerEnvironment::step(float dtime)
for (auto &ao_it : m_active_objects) { for (auto &ao_it : m_active_objects) {
ServerActiveObject* obj = ao_it.second; ServerActiveObject* obj = ao_it.second;
// Don't step if is to be removed or stored statically if (obj->isGone())
if(obj->m_removed || obj->m_pending_deactivation)
continue; continue;
// Step object // Step object
obj->step(dtime, send_recommended); obj->step(dtime, send_recommended);
// Read messages from object // Read messages from object
while(!obj->m_messages_out.empty()) while (!obj->m_messages_out.empty()) {
{ m_active_object_messages.push(obj->m_messages_out.front());
m_active_object_messages.push(
obj->m_messages_out.front());
obj->m_messages_out.pop(); obj->m_messages_out.pop();
} }
} }
@ -1322,9 +1313,6 @@ void ServerEnvironment::step(float dtime)
*/ */
if (m_object_management_interval.step(dtime, 0.5)) { if (m_object_management_interval.step(dtime, 0.5)) {
ScopeProfiler sp(g_profiler, "SEnv: remove removed objs avg /.5s", SPT_AVG); ScopeProfiler sp(g_profiler, "SEnv: remove removed objs avg /.5s", SPT_AVG);
/*
Remove objects that satisfy (m_removed && m_known_by_count==0)
*/
removeRemovedObjects(); removeRemovedObjects();
} }
@ -1444,7 +1432,7 @@ void ServerEnvironment::getAddedActiveObjects(PlayerSAO *playersao, s16 radius,
player_radius_f = 0; player_radius_f = 0;
/* /*
Go through the object list, Go through the object list,
- discard m_removed objects, - discard removed/deactivated objects,
- discard objects that are too far away, - discard objects that are too far away,
- discard objects that are found in current_objects. - discard objects that are found in current_objects.
- add remaining objects to added_objects - add remaining objects to added_objects
@ -1457,8 +1445,7 @@ void ServerEnvironment::getAddedActiveObjects(PlayerSAO *playersao, s16 radius,
if (object == NULL) if (object == NULL)
continue; continue;
// Discard if removed or deactivating if (object->isGone())
if(object->m_removed || object->m_pending_deactivation)
continue; continue;
f32 distance_f = object->getBasePosition(). f32 distance_f = object->getBasePosition().
@ -1497,9 +1484,9 @@ void ServerEnvironment::getRemovedActiveObjects(PlayerSAO *playersao, s16 radius
/* /*
Go through current_objects; object is removed if: Go through current_objects; object is removed if:
- object is not found in m_active_objects (this is actually an - object is not found in m_active_objects (this is actually an
error condition; objects should be set m_removed=true and removed error condition; objects should be removed only after all clients
only after all clients have been informed about removal), or have been informed about removal), or
- object has m_removed=true, or - object is to be removed or deactivated, or
- object is too far away - object is too far away
*/ */
for (u16 id : current_objects) { for (u16 id : current_objects) {
@ -1512,7 +1499,7 @@ void ServerEnvironment::getRemovedActiveObjects(PlayerSAO *playersao, s16 radius
continue; continue;
} }
if (object->m_removed || object->m_pending_deactivation) { if (object->isGone()) {
removed_objects.push(id); removed_objects.push(id);
continue; continue;
} }
@ -1684,7 +1671,7 @@ u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
} }
/* /*
Remove objects that satisfy (m_removed && m_known_by_count==0) Remove objects that satisfy (isGone() && m_known_by_count==0)
*/ */
void ServerEnvironment::removeRemovedObjects() void ServerEnvironment::removeRemovedObjects()
{ {
@ -1692,62 +1679,54 @@ void ServerEnvironment::removeRemovedObjects()
for (auto &ao_it : m_active_objects) { for (auto &ao_it : m_active_objects) {
u16 id = ao_it.first; u16 id = ao_it.first;
ServerActiveObject* obj = ao_it.second; ServerActiveObject* obj = ao_it.second;
// This shouldn't happen but check it // This shouldn't happen but check it
if(obj == NULL) if (!obj) {
{ errorstream << "ServerEnvironment::removeRemovedObjects(): "
infostream<<"NULL object found in ServerEnvironment" << "NULL object found. id=" << id << std::endl;
<<" while finding removed objects. id="<<id<<std::endl;
// Id to be removed from m_active_objects
objects_to_remove.push_back(id); objects_to_remove.push_back(id);
continue; continue;
} }
/* /*
We will delete objects that are marked as removed or thatare We will handle objects marked for removal or deactivation
waiting for deletion after deactivation
*/ */
if (!obj->m_removed && !obj->m_pending_deactivation) if (!obj->isGone())
continue; continue;
/* /*
Delete static data from block if is marked as removed Delete static data from block if removed
*/ */
if(obj->m_static_exists && obj->m_removed) if (obj->m_pending_removal)
{ deleteStaticFromBlock(obj, id, MOD_REASON_REMOVE_OBJECTS_REMOVE, false);
MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
if (block) {
block->m_static_objects.remove(id);
block->raiseModified(MOD_STATE_WRITE_NEEDED,
MOD_REASON_REMOVE_OBJECTS_REMOVE);
obj->m_static_exists = false;
} else {
infostream<<"Failed to emerge block from which an object to "
<<"be removed was loaded from. id="<<id<<std::endl;
}
}
// If m_known_by_count > 0, don't actually remove. On some future // If still known by clients, don't actually remove. On some future
// invocation this will be 0, which is when removal will continue. // invocation this will be 0, which is when removal will continue.
if(obj->m_known_by_count > 0) if(obj->m_known_by_count > 0)
continue; continue;
/* /*
Move static data from active to stored if not marked as removed Move static data from active to stored if deactivated
*/ */
if(obj->m_static_exists && !obj->m_removed){ if (!obj->m_pending_removal && 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) {
std::map<u16, StaticObject>::iterator i = std::map<u16, StaticObject>::iterator i =
block->m_static_objects.m_active.find(id); block->m_static_objects.m_active.find(id);
if(i != block->m_static_objects.m_active.end()){ if (i != block->m_static_objects.m_active.end()) {
block->m_static_objects.m_stored.push_back(i->second); block->m_static_objects.m_stored.push_back(i->second);
block->m_static_objects.m_active.erase(id); block->m_static_objects.m_active.erase(id);
block->raiseModified(MOD_STATE_WRITE_NEEDED, block->raiseModified(MOD_STATE_WRITE_NEEDED,
MOD_REASON_REMOVE_OBJECTS_DEACTIVATE); MOD_REASON_REMOVE_OBJECTS_DEACTIVATE);
} else {
warningstream << "ServerEnvironment::removeRemovedObjects(): "
<< "id=" << id << " m_static_exists=true but "
<< "static data doesn't actually exist in "
<< PP(obj->m_static_block) << std::endl;
} }
} else { } else {
infostream<<"Failed to emerge block from which an object to " infostream << "Failed to emerge block from which an object to "
<<"be deactivated was loaded from. id="<<id<<std::endl; << "be deactivated was loaded from. id=" << id << std::endl;
} }
} }
@ -1760,7 +1739,6 @@ void ServerEnvironment::removeRemovedObjects()
if(obj->environmentDeletes()) if(obj->environmentDeletes())
delete obj; delete obj;
// Id to be removed from m_active_objects
objects_to_remove.push_back(id); objects_to_remove.push_back(id);
} }
// Remove references from m_active_objects // Remove references from m_active_objects
@ -1855,6 +1833,7 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
// This will also add the object to the active static list // This will also add the object to the active static list
addActiveObjectRaw(obj, false, dtime_s); addActiveObjectRaw(obj, false, dtime_s);
} }
// Clear stored list // Clear stored list
block->m_static_objects.m_stored.clear(); block->m_static_objects.m_stored.clear();
// Add leftover failed stuff to stored list // Add leftover failed stuff to stored list
@ -1862,15 +1841,6 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
block->m_static_objects.m_stored.push_back(s_obj); block->m_static_objects.m_stored.push_back(s_obj);
} }
// Turn the active counterparts of activated objects not pending for
// deactivation
for (auto &i : block->m_static_objects.m_active) {
u16 id = i.first;
ServerActiveObject *object = getActiveObject(id);
assert(object);
object->m_pending_deactivation = false;
}
/* /*
Note: Block hasn't really been modified here. Note: Block hasn't really been modified here.
The objects have just been activated and moved from the stored The objects have just been activated and moved from the stored
@ -1906,8 +1876,8 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
if(!force_delete && !obj->isStaticAllowed()) if(!force_delete && !obj->isStaticAllowed())
continue; continue;
// If pending deactivation, let removeRemovedObjects() do it // removeRemovedObjects() is responsible for these
if(!force_delete && obj->m_pending_deactivation) if(!force_delete && obj->isGone())
continue; continue;
u16 id = ao_it.first; u16 id = ao_it.first;
@ -1924,47 +1894,25 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
!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))
{ {
v3s16 old_static_block = obj->m_static_block; // Delete from block where object was located
deleteStaticFromBlock(obj, id, MOD_REASON_STATIC_DATA_REMOVED, false);
// Save to block where object is located
MapBlock *block = m_map->emergeBlock(blockpos_o, false);
if(!block){
errorstream<<"ServerEnvironment::deactivateFarObjects(): "
<<"Could not save object id="<<id
<<" to it's current block "<<PP(blockpos_o)
<<std::endl;
continue;
}
std::string staticdata_new; std::string staticdata_new;
obj->getStaticData(&staticdata_new); obj->getStaticData(&staticdata_new);
StaticObject s_obj(obj->getType(), objectpos, staticdata_new); StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
block->m_static_objects.insert(id, s_obj); // Save to block where object is located
obj->m_static_block = blockpos_o; saveStaticToBlock(blockpos_o, id, obj, s_obj, MOD_REASON_STATIC_DATA_ADDED);
block->raiseModified(MOD_STATE_WRITE_NEEDED,
MOD_REASON_STATIC_DATA_ADDED);
// Delete from block where object was located
block = m_map->emergeBlock(old_static_block, false);
if(!block){
errorstream<<"ServerEnvironment::deactivateFarObjects(): "
<<"Could not delete object id="<<id
<<" from it's previous block "<<PP(old_static_block)
<<std::endl;
continue;
}
block->m_static_objects.remove(id);
block->raiseModified(MOD_STATE_WRITE_NEEDED,
MOD_REASON_STATIC_DATA_REMOVED);
continue; continue;
} }
// If block is active, don't remove // If block is still active, don't remove
if(!force_delete && m_active_blocks.contains(blockpos_o)) if(!force_delete && m_active_blocks.contains(blockpos_o))
continue; continue;
verbosestream<<"ServerEnvironment::deactivateFarObjects(): " verbosestream << "ServerEnvironment::deactivateFarObjects(): "
<<"deactivating object id="<<id<<" on inactive block " << "deactivating object id=" << id << " on inactive block "
<<PP(blockpos_o)<<std::endl; << PP(blockpos_o) << std::endl;
// If known by some client, don't immediately delete. // If known by some client, don't immediately delete.
bool pending_delete = (obj->m_known_by_count > 0 && !force_delete); bool pending_delete = (obj->m_known_by_count > 0 && !force_delete);
@ -1972,7 +1920,6 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
/* /*
Update the static data Update the static data
*/ */
if(obj->isStaticAllowed()) if(obj->isStaticAllowed())
{ {
// Create new static object // Create new static object
@ -1983,6 +1930,7 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
bool stays_in_same_block = false; bool stays_in_same_block = false;
bool data_changed = true; bool data_changed = true;
// Check if static data has changed considerably
if (obj->m_static_exists) { if (obj->m_static_exists) {
if (obj->m_static_block == blockpos_o) if (obj->m_static_block == blockpos_o)
stays_in_same_block = true; stays_in_same_block = true;
@ -2001,108 +1949,47 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
(static_old.pos - objectpos).getLength() < save_movem) (static_old.pos - objectpos).getLength() < save_movem)
data_changed = false; data_changed = false;
} else { } else {
errorstream<<"ServerEnvironment::deactivateFarObjects(): " warningstream << "ServerEnvironment::deactivateFarObjects(): "
<<"id="<<id<<" m_static_exists=true but " << "id=" << id << " m_static_exists=true but "
<<"static data doesn't actually exist in " << "static data doesn't actually exist in "
<<PP(obj->m_static_block)<<std::endl; << PP(obj->m_static_block) << std::endl;
} }
} }
} }
/*
While changes are always saved, blocks are only marked as modified
if the object has moved or different staticdata. (see above)
*/
bool shall_be_written = (!stays_in_same_block || data_changed); bool shall_be_written = (!stays_in_same_block || data_changed);
u32 reason = shall_be_written ? MOD_REASON_STATIC_DATA_CHANGED : MOD_REASON_UNKNOWN;
// Delete old static object // Delete old static object
if(obj->m_static_exists) deleteStaticFromBlock(obj, id, reason, false);
{
MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
if(block)
{
block->m_static_objects.remove(id);
obj->m_static_exists = false;
// Only mark block as modified if data changed considerably
if(shall_be_written)
block->raiseModified(MOD_STATE_WRITE_NEEDED,
MOD_REASON_STATIC_DATA_CHANGED);
}
}
// Add to the block where the object is located in // Add to the block where the object is located in
v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS)); v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
// Get or generate the block u16 store_id = pending_delete ? id : 0;
MapBlock *block = NULL; if (!saveStaticToBlock(blockpos, store_id, obj, s_obj, reason))
try{ force_delete = true;
block = m_map->emergeBlock(blockpos);
} catch(InvalidPositionException &e){
// Handled via NULL pointer
// NOTE: emergeBlock's failure is usually determined by it
// actually returning NULL
}
if(block)
{
if (block->m_static_objects.m_stored.size() >= g_settings->getU16("max_objects_per_block")) {
warningstream << "ServerEnv: Trying to store id = " << obj->getId()
<< " statically but block " << PP(blockpos)
<< " already contains "
<< block->m_static_objects.m_stored.size()
<< " objects."
<< " Forcing delete." << std::endl;
force_delete = true;
} else {
// If static counterpart already exists in target block,
// remove it first.
// This shouldn't happen because the object is removed from
// the previous block before this according to
// obj->m_static_block, but happens rarely for some unknown
// reason. Unsuccessful attempts have been made to find
// said reason.
if(id && block->m_static_objects.m_active.find(id) != block->m_static_objects.m_active.end()){
warningstream<<"ServerEnv: Performing hack #83274"
<<std::endl;
block->m_static_objects.remove(id);
}
// Store static data
u16 store_id = pending_delete ? id : 0;
block->m_static_objects.insert(store_id, s_obj);
// Only mark block as modified if data changed considerably
if(shall_be_written)
block->raiseModified(MOD_STATE_WRITE_NEEDED,
MOD_REASON_STATIC_DATA_CHANGED);
obj->m_static_exists = true;
obj->m_static_block = block->getPos();
}
}
else{
if(!force_delete){
v3s16 p = floatToInt(objectpos, BS);
errorstream<<"ServerEnv: Could not find or generate "
<<"a block for storing id="<<obj->getId()
<<" statically (pos="<<PP(p)<<")"<<std::endl;
continue;
}
}
} }
/* /*
If known by some client, set pending deactivation. If known by some client, set pending deactivation.
Otherwise delete it immediately. Otherwise delete it immediately.
*/ */
if(pending_delete && !force_delete) if(pending_delete && !force_delete)
{ {
verbosestream<<"ServerEnvironment::deactivateFarObjects(): " verbosestream << "ServerEnvironment::deactivateFarObjects(): "
<<"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; obj->m_pending_deactivation = true;
continue; continue;
} }
verbosestream << "ServerEnvironment::deactivateFarObjects(): "
verbosestream<<"ServerEnvironment::deactivateFarObjects(): " << "object id=" << id << " is not known by clients"
<<"object id="<<id<<" is not known by clients" << "; deleting" << std::endl;
<<"; deleting"<<std::endl;
// Tell the object about removal // Tell the object about removal
obj->removingFromEnvironment(); obj->removingFromEnvironment();
@ -2122,6 +2009,69 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete)
} }
} }
void ServerEnvironment::deleteStaticFromBlock(
ServerActiveObject *obj, u16 id, u32 mod_reason, bool no_emerge)
{
if (!obj->m_static_exists)
return;
MapBlock *block;
if (no_emerge)
block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
else
block = m_map->emergeBlock(obj->m_static_block, false);
if (!block) {
if (!no_emerge)
errorstream << "ServerEnv: Failed to emerge block " << PP(obj->m_static_block)
<< " when deleting static data of object from it. id=" << id << std::endl;
return;
}
block->m_static_objects.remove(id);
if (mod_reason != MOD_REASON_UNKNOWN) // Do not mark as modified if requested
block->raiseModified(MOD_STATE_WRITE_NEEDED, mod_reason);
obj->m_static_exists = false;
}
bool ServerEnvironment::saveStaticToBlock(
v3s16 blockpos, u16 store_id,
ServerActiveObject *obj, const StaticObject &s_obj,
u32 mod_reason)
{
MapBlock *block = nullptr;
try {
block = m_map->emergeBlock(blockpos);
} catch (InvalidPositionException &e) {
// Handled via NULL pointer
// NOTE: emergeBlock's failure is usually determined by it
// actually returning NULL
}
if (!block) {
errorstream << "ServerEnv: Failed to emerge block " << PP(obj->m_static_block)
<< " when saving static data of object to it. id=" << store_id << std::endl;
return false;
}
if (block->m_static_objects.m_stored.size() >= g_settings->getU16("max_objects_per_block")) {
warningstream << "ServerEnv: Trying to store id = " << store_id
<< " statically but block " << PP(blockpos)
<< " already contains "
<< block->m_static_objects.m_stored.size()
<< " objects." << std::endl;
return false;
}
block->m_static_objects.insert(store_id, s_obj);
if (mod_reason != MOD_REASON_UNKNOWN) // Do not mark as modified if requested
block->raiseModified(MOD_STATE_WRITE_NEEDED, mod_reason);
obj->m_static_exists = true;
obj->m_static_block = blockpos;
return true;
}
PlayerDatabase *ServerEnvironment::openPlayerDatabase(const std::string &name, PlayerDatabase *ServerEnvironment::openPlayerDatabase(const std::string &name,
const std::string &savedir, const Settings &conf) const std::string &savedir, const Settings &conf)
{ {

View File

@ -35,6 +35,7 @@ class PlayerDatabase;
class PlayerSAO; class PlayerSAO;
class ServerEnvironment; class ServerEnvironment;
class ActiveBlockModifier; class ActiveBlockModifier;
struct StaticObject;
class ServerActiveObject; class ServerActiveObject;
class Server; class Server;
class ServerScripting; class ServerScripting;
@ -368,7 +369,7 @@ private:
u16 addActiveObjectRaw(ServerActiveObject *object, bool set_changed, u32 dtime_s); u16 addActiveObjectRaw(ServerActiveObject *object, bool set_changed, u32 dtime_s);
/* /*
Remove all objects that satisfy (m_removed && m_known_by_count==0) Remove all objects that satisfy (isGone() && m_known_by_count==0)
*/ */
void removeRemovedObjects(); void removeRemovedObjects();
@ -388,6 +389,14 @@ private:
*/ */
void deactivateFarObjects(bool force_delete); void deactivateFarObjects(bool force_delete);
/*
A few helpers used by the three above methods
*/
void deleteStaticFromBlock(
ServerActiveObject *obj, u16 id, u32 mod_reason, bool no_emerge);
bool saveStaticToBlock(v3s16 blockpos, u16 store_id,
ServerActiveObject *obj, const StaticObject &s_obj, u32 mod_reason);
/* /*
Member variables Member variables
*/ */

View File

@ -212,23 +212,27 @@ public:
it anymore. it anymore.
- Removal is delayed to preserve the id for the time during which - Removal is delayed to preserve the id for the time during which
it could be confused to some other object by some client. it could be confused to some other object by some client.
- This is set to true by the step() method when the object wants - This is usually set to true by the step() method when the object wants
to be deleted. to be deleted but can be set by anything else too.
- This can be set to true by anything else too.
*/ */
bool m_removed = false; bool m_pending_removal = false;
/* /*
This is set to true when an object should be removed from the active Same purpose as m_pending_removal but for deactivation.
object list but couldn't be removed because the id has to be deactvation = save static data in block, remove active object
reserved for some client.
The environment checks this periodically. If this is true and also If this is set alongside with m_pending_removal, removal takes
m_known_by_count is true, object is deleted from the active object priority.
list.
*/ */
bool m_pending_deactivation = false; bool m_pending_deactivation = false;
/*
A getter that unifies the above to answer the question:
"Can the environment still interact with this object?"
*/
inline bool isGone() const
{ return m_pending_removal || m_pending_deactivation; }
/* /*
Whether the object's static data has been stored to a block Whether the object's static data has been stored to a block
*/ */