<< "Removing all active objects" << std::endl;
std::vector<u16> objects_to_remove;
for (auto &it : m_active_objects) {
+ u16 id = it.first;
ServerActiveObject* obj = it.second;
if (obj->getType() == ACTIVEOBJECT_TYPE_PLAYER)
continue;
- u16 id = it.first;
+
// Delete static object if block is loaded
- if (obj->m_static_exists) {
- 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;
- }
- }
+ deleteStaticFromBlock(obj, id, MOD_REASON_CLEAR_ALL_OBJECTS, true);
+
// If known by some client, don't delete immediately
if (obj->m_known_by_count > 0) {
- obj->m_pending_deactivation = true;
- obj->m_removed = true;
+ obj->m_pending_removal = true;
continue;
}
for (auto &ao_it : m_active_objects) {
ServerActiveObject* obj = ao_it.second;
- // Don't step if is to be removed or stored statically
- if(obj->m_removed || obj->m_pending_deactivation)
+ if (obj->isGone())
continue;
+
// Step object
obj->step(dtime, send_recommended);
// Read messages from object
- while(!obj->m_messages_out.empty())
- {
- m_active_object_messages.push(
- obj->m_messages_out.front());
+ while (!obj->m_messages_out.empty()) {
+ m_active_object_messages.push(obj->m_messages_out.front());
obj->m_messages_out.pop();
}
}
*/
if (m_object_management_interval.step(dtime, 0.5)) {
ScopeProfiler sp(g_profiler, "SEnv: remove removed objs avg /.5s", SPT_AVG);
- /*
- Remove objects that satisfy (m_removed && m_known_by_count==0)
- */
removeRemovedObjects();
}
player_radius_f = 0;
/*
Go through the object list,
- - discard m_removed objects,
+ - discard removed/deactivated objects,
- discard objects that are too far away,
- discard objects that are found in current_objects.
- add remaining objects to added_objects
if (object == NULL)
continue;
- // Discard if removed or deactivating
- if(object->m_removed || object->m_pending_deactivation)
+ if (object->isGone())
continue;
f32 distance_f = object->getBasePosition().
/*
Go through current_objects; object is removed if:
- object is not found in m_active_objects (this is actually an
- error condition; objects should be set m_removed=true and removed
- only after all clients have been informed about removal), or
- - object has m_removed=true, or
+ error condition; objects should be removed only after all clients
+ have been informed about removal), or
+ - object is to be removed or deactivated, or
- object is too far away
*/
for (u16 id : current_objects) {
continue;
}
- if (object->m_removed || object->m_pending_deactivation) {
+ if (object->isGone()) {
removed_objects.push(id);
continue;
}
}
/*
- Remove objects that satisfy (m_removed && m_known_by_count==0)
+ Remove objects that satisfy (isGone() && m_known_by_count==0)
*/
void ServerEnvironment::removeRemovedObjects()
{
for (auto &ao_it : m_active_objects) {
u16 id = ao_it.first;
ServerActiveObject* obj = ao_it.second;
+
// This shouldn't happen but check it
- if(obj == NULL)
- {
- infostream<<"NULL object found in ServerEnvironment"
- <<" while finding removed objects. id="<<id<<std::endl;
- // Id to be removed from m_active_objects
+ if (!obj) {
+ errorstream << "ServerEnvironment::removeRemovedObjects(): "
+ << "NULL object found. id=" << id << std::endl;
objects_to_remove.push_back(id);
continue;
}
/*
- We will delete objects that are marked as removed or thatare
- waiting for deletion after deactivation
+ We will handle objects marked for removal or deactivation
*/
- if (!obj->m_removed && !obj->m_pending_deactivation)
+ if (!obj->isGone())
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)
- {
- 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 (obj->m_pending_removal)
+ deleteStaticFromBlock(obj, id, MOD_REASON_REMOVE_OBJECTS_REMOVE, false);
- // 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.
if(obj->m_known_by_count > 0)
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);
if (block) {
std::map<u16, StaticObject>::iterator i =
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_active.erase(id);
block->raiseModified(MOD_STATE_WRITE_NEEDED,
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 {
- infostream<<"Failed to emerge block from which an object to "
- <<"be deactivated was loaded from. id="<<id<<std::endl;
+ infostream << "Failed to emerge block from which an object to "
+ << "be deactivated was loaded from. id=" << id << std::endl;
}
}
if(obj->environmentDeletes())
delete obj;
- // Id to be removed from m_active_objects
objects_to_remove.push_back(id);
}
// Remove references from m_active_objects
// This will also add the object to the active static list
addActiveObjectRaw(obj, false, dtime_s);
}
+
// Clear stored list
block->m_static_objects.m_stored.clear();
// Add leftover failed stuff to stored list
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.
The objects have just been activated and moved from the stored
if(!force_delete && !obj->isStaticAllowed())
continue;
- // If pending deactivation, let removeRemovedObjects() do it
- if(!force_delete && obj->m_pending_deactivation)
+ // removeRemovedObjects() is responsible for these
+ if(!force_delete && obj->isGone())
continue;
u16 id = ao_it.first;
!m_active_blocks.contains(obj->m_static_block) &&
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;
obj->getStaticData(&staticdata_new);
StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
- block->m_static_objects.insert(id, s_obj);
- obj->m_static_block = blockpos_o;
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_STATIC_DATA_ADDED);
+ // Save to block where object is located
+ saveStaticToBlock(blockpos_o, id, obj, s_obj, 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;
}
- // If block is active, don't remove
+ // If block is still active, don't remove
if(!force_delete && m_active_blocks.contains(blockpos_o))
continue;
- verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
- <<"deactivating object id="<<id<<" on inactive block "
- <<PP(blockpos_o)<<std::endl;
+ verbosestream << "ServerEnvironment::deactivateFarObjects(): "
+ << "deactivating object id=" << id << " on inactive block "
+ << PP(blockpos_o) << std::endl;
// If known by some client, don't immediately delete.
bool pending_delete = (obj->m_known_by_count > 0 && !force_delete);
/*
Update the static data
*/
-
if(obj->isStaticAllowed())
{
// Create new static object
bool stays_in_same_block = false;
bool data_changed = true;
+ // Check if static data has changed considerably
if (obj->m_static_exists) {
if (obj->m_static_block == blockpos_o)
stays_in_same_block = true;
(static_old.pos - objectpos).getLength() < save_movem)
data_changed = false;
} else {
- errorstream<<"ServerEnvironment::deactivateFarObjects(): "
- <<"id="<<id<<" m_static_exists=true but "
- <<"static data doesn't actually exist in "
- <<PP(obj->m_static_block)<<std::endl;
+ warningstream << "ServerEnvironment::deactivateFarObjects(): "
+ << "id=" << id << " m_static_exists=true but "
+ << "static data doesn't actually exist in "
+ << 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);
+ u32 reason = shall_be_written ? MOD_REASON_STATIC_DATA_CHANGED : MOD_REASON_UNKNOWN;
// Delete old static object
- if(obj->m_static_exists)
- {
- 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);
- }
- }
+ deleteStaticFromBlock(obj, id, reason, false);
// Add to the block where the object is located in
v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
- // Get or generate the block
- MapBlock *block = NULL;
- 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)
- {
- 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;
- }
- }
+ u16 store_id = pending_delete ? id : 0;
+ if (!saveStaticToBlock(blockpos, store_id, obj, s_obj, reason))
+ force_delete = true;
}
/*
If known by some client, set pending deactivation.
Otherwise delete it immediately.
*/
-
if(pending_delete && !force_delete)
{
- verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
- <<"object id="<<id<<" is known by clients"
- <<"; not deleting yet"<<std::endl;
+ verbosestream << "ServerEnvironment::deactivateFarObjects(): "
+ << "object id=" << id << " is known by clients"
+ << "; not deleting yet" << std::endl;
obj->m_pending_deactivation = true;
continue;
}
-
- verbosestream<<"ServerEnvironment::deactivateFarObjects(): "
- <<"object id="<<id<<" is not known by clients"
- <<"; deleting"<<std::endl;
+ verbosestream << "ServerEnvironment::deactivateFarObjects(): "
+ << "object id=" << id << " is not known by clients"
+ << "; deleting" << std::endl;
// Tell the object about removal
obj->removingFromEnvironment();
}
}
+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,
const std::string &savedir, const Settings &conf)
{