- // Remove objects in all loadable blocks
- u32 unload_interval = g_settings->getS32("max_clearobjects_extra_loaded_blocks");
- unload_interval = MYMAX(unload_interval, 1);
- u32 report_interval = loadable_blocks.size() / 10;
- u32 num_blocks_checked = 0;
- u32 num_blocks_cleared = 0;
- u32 num_objs_cleared = 0;
- for(std::vector<v3s16>::iterator i = loadable_blocks.begin();
- i != loadable_blocks.end(); ++i) {
- v3s16 p = *i;
- MapBlock *block = m_map->emergeBlock(p, false);
- if(!block){
- errorstream<<"ServerEnvironment::clearAllObjects(): "
- <<"Failed to emerge block "<<PP(p)<<std::endl;
- continue;
- }
- u32 num_stored = block->m_static_objects.m_stored.size();
- u32 num_active = block->m_static_objects.m_active.size();
- if(num_stored != 0 || num_active != 0){
- block->m_static_objects.m_stored.clear();
- block->m_static_objects.m_active.clear();
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_CLEAR_ALL_OBJECTS);
- num_objs_cleared += num_stored + num_active;
- num_blocks_cleared++;
- }
- num_blocks_checked++;
-
- if(report_interval != 0 &&
- num_blocks_checked % report_interval == 0){
- float percent = 100.0 * (float)num_blocks_checked /
- loadable_blocks.size();
- infostream<<"ServerEnvironment::clearAllObjects(): "
- <<"Cleared "<<num_objs_cleared<<" objects"
- <<" in "<<num_blocks_cleared<<" blocks ("
- <<percent<<"%)"<<std::endl;
- }
- if(num_blocks_checked % unload_interval == 0){
- m_map->unloadUnreferencedBlocks();
- }
- }
- m_map->unloadUnreferencedBlocks();
-
- // Drop references that were added above
- for(std::vector<v3s16>::iterator i = loaded_blocks.begin();
- i != loaded_blocks.end(); ++i) {
- v3s16 p = *i;
- MapBlock *block = m_map->getBlockNoCreateNoEx(p);
- assert(block);
- block->refDrop();
- }
-
- infostream<<"ServerEnvironment::clearAllObjects(): "
- <<"Finished: Cleared "<<num_objs_cleared<<" objects"
- <<" in "<<num_blocks_cleared<<" blocks"<<std::endl;
-}
-
-void ServerEnvironment::step(float dtime)
-{
- DSTACK(FUNCTION_NAME);
-
- //TimeTaker timer("ServerEnv step");
-
- /* Step time of day */
- stepTimeOfDay(dtime);
-
- // Update this one
- // NOTE: This is kind of funny on a singleplayer game, but doesn't
- // really matter that much.
- m_recommended_send_interval = g_settings->getFloat("dedicated_server_step");
-
- /*
- Increment game time
- */
- {
- m_game_time_fraction_counter += dtime;
- u32 inc_i = (u32)m_game_time_fraction_counter;
- m_game_time += inc_i;
- m_game_time_fraction_counter -= (float)inc_i;
- }
-
- /*
- Handle players
- */
- {
- ScopeProfiler sp(g_profiler, "SEnv: handle players avg", SPT_AVG);
- for(std::vector<Player*>::iterator i = m_players.begin();
- i != m_players.end(); ++i)
- {
- Player *player = *i;
-
- // Ignore disconnected players
- if(player->peer_id == 0)
- continue;
-
- // Move
- player->move(dtime, this, 100*BS);
- }
- }
-
- /*
- Manage active block list
- */
- if(m_active_blocks_management_interval.step(dtime, 2.0))
- {
- ScopeProfiler sp(g_profiler, "SEnv: manage act. block list avg /2s", SPT_AVG);
- /*
- Get player block positions
- */
- std::vector<v3s16> players_blockpos;
- for(std::vector<Player*>::iterator
- i = m_players.begin();
- i != m_players.end(); ++i) {
- Player *player = *i;
- // Ignore disconnected players
- if(player->peer_id == 0)
- continue;
-
- v3s16 blockpos = getNodeBlockPos(
- floatToInt(player->getPosition(), BS));
- players_blockpos.push_back(blockpos);
- }
-
- /*
- Update list of active blocks, collecting changes
- */
- const s16 active_block_range = g_settings->getS16("active_block_range");
- std::set<v3s16> blocks_removed;
- std::set<v3s16> blocks_added;
- m_active_blocks.update(players_blockpos, active_block_range,
- blocks_removed, blocks_added);
-
- /*
- Handle removed blocks
- */
-
- // Convert active objects that are no more in active blocks to static
- deactivateFarObjects(false);
-
- for(std::set<v3s16>::iterator
- i = blocks_removed.begin();
- i != blocks_removed.end(); ++i)
- {
- v3s16 p = *i;
-
- /* infostream<<"Server: Block " << PP(p)
- << " became inactive"<<std::endl; */
-
- MapBlock *block = m_map->getBlockNoCreateNoEx(p);
- if(block==NULL)
- continue;
-
- // Set current time as timestamp (and let it set ChangedFlag)
- block->setTimestamp(m_game_time);
- }
-
- /*
- Handle added blocks
- */
-
- for(std::set<v3s16>::iterator
- i = blocks_added.begin();
- i != blocks_added.end(); ++i)
- {
- v3s16 p = *i;
-
- MapBlock *block = m_map->getBlockOrEmerge(p);
- if(block==NULL){
- m_active_blocks.m_list.erase(p);
- continue;
- }
-
- activateBlock(block);
- /* infostream<<"Server: Block " << PP(p)
- << " became active"<<std::endl; */
- }
- }
-
- /*
- Mess around in active blocks
- */
- if(m_active_blocks_nodemetadata_interval.step(dtime, 1.0))
- {
- ScopeProfiler sp(g_profiler, "SEnv: mess in act. blocks avg /1s", SPT_AVG);
-
- float dtime = 1.0;
-
- for(std::set<v3s16>::iterator
- i = m_active_blocks.m_list.begin();
- i != m_active_blocks.m_list.end(); ++i)
- {
- v3s16 p = *i;
-
- /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
- <<") being handled"<<std::endl;*/
-
- MapBlock *block = m_map->getBlockNoCreateNoEx(p);
- if(block==NULL)
- continue;
-
- // Reset block usage timer
- block->resetUsageTimer();
-
- // Set current time as timestamp
- block->setTimestampNoChangedFlag(m_game_time);
- // If time has changed much from the one on disk,
- // set block to be saved when it is unloaded
- if(block->getTimestamp() > block->getDiskTimestamp() + 60)
- block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
- MOD_REASON_BLOCK_EXPIRED);
-
- // Run node timers
- std::map<v3s16, NodeTimer> elapsed_timers =
- block->m_node_timers.step((float)dtime);
- if(!elapsed_timers.empty()){
- MapNode n;
- for(std::map<v3s16, NodeTimer>::iterator
- i = elapsed_timers.begin();
- i != elapsed_timers.end(); ++i){
- n = block->getNodeNoEx(i->first);
- p = i->first + block->getPosRelative();
- if(m_script->node_on_timer(p,n,i->second.elapsed))
- block->setNodeTimer(i->first,NodeTimer(i->second.timeout,0));
- }
- }
- }
- }
-
- const float abm_interval = 1.0;
- if(m_active_block_modifier_interval.step(dtime, abm_interval))
- do{ // breakable
- if(m_active_block_interval_overload_skip > 0){
- ScopeProfiler sp(g_profiler, "SEnv: ABM overload skips");
- m_active_block_interval_overload_skip--;
- break;
- }
- ScopeProfiler sp(g_profiler, "SEnv: modify in blocks avg /1s", SPT_AVG);
- TimeTaker timer("modify in active blocks");
-
- // Initialize handling of ActiveBlockModifiers
- ABMHandler abmhandler(m_abms, abm_interval, this, true);
-
- for(std::set<v3s16>::iterator
- i = m_active_blocks.m_list.begin();
- i != m_active_blocks.m_list.end(); ++i)
- {
- v3s16 p = *i;
-
- /*infostream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
- <<") being handled"<<std::endl;*/
-
- MapBlock *block = m_map->getBlockNoCreateNoEx(p);
- if(block == NULL)
- continue;
-
- // Set current time as timestamp
- block->setTimestampNoChangedFlag(m_game_time);
-
- /* Handle ActiveBlockModifiers */
- abmhandler.apply(block);
- }
-
- u32 time_ms = timer.stop(true);
- u32 max_time_ms = 200;
- if(time_ms > max_time_ms){
- warningstream<<"active block modifiers took "
- <<time_ms<<"ms (longer than "
- <<max_time_ms<<"ms)"<<std::endl;
- m_active_block_interval_overload_skip = (time_ms / max_time_ms) + 1;
- }
- }while(0);
-
- /*
- Step script environment (run global on_step())
- */
- m_script->environment_Step(dtime);
-
- /*
- Step active objects
- */
- {
- ScopeProfiler sp(g_profiler, "SEnv: step act. objs avg", SPT_AVG);
- //TimeTaker timer("Step active objects");
-
- g_profiler->avg("SEnv: num of objects", m_active_objects.size());
-
- // This helps the objects to send data at the same time
- bool send_recommended = false;
- m_send_recommended_timer += dtime;
- if(m_send_recommended_timer > getSendRecommendedInterval())
- {
- m_send_recommended_timer -= getSendRecommendedInterval();
- send_recommended = true;
- }
-
- for(std::map<u16, ServerActiveObject*>::iterator
- i = m_active_objects.begin();
- i != m_active_objects.end(); ++i)
- {
- ServerActiveObject* obj = i->second;
- // Don't step if is to be removed or stored statically
- if(obj->m_removed || obj->m_pending_deactivation)
- 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());
- obj->m_messages_out.pop();
- }
- }
- }
-
- /*
- Manage active objects
- */
- 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();
- }
-}
-
-ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
-{
- std::map<u16, ServerActiveObject*>::iterator n;
- n = m_active_objects.find(id);
- if(n == m_active_objects.end())
- return NULL;
- return n->second;
-}
-
-bool isFreeServerActiveObjectId(u16 id,
- std::map<u16, ServerActiveObject*> &objects)
-{
- if(id == 0)
- return false;
-
- return objects.find(id) == objects.end();
-}
-
-u16 getFreeServerActiveObjectId(
- std::map<u16, ServerActiveObject*> &objects)
-{
- //try to reuse id's as late as possible
- static u16 last_used_id = 0;
- u16 startid = last_used_id;
- for(;;)
- {
- last_used_id ++;
- if(isFreeServerActiveObjectId(last_used_id, objects))
- return last_used_id;
-
- if(last_used_id == startid)
- return 0;
- }
-}
-
-u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
-{
- assert(object); // Pre-condition
- m_added_objects++;
- u16 id = addActiveObjectRaw(object, true, 0);
- return id;
-}
-
-/*
- Finds out what new objects have been added to
- inside a radius around a position
-*/
-void ServerEnvironment::getAddedActiveObjects(Player *player, s16 radius,
- s16 player_radius,
- std::set<u16> ¤t_objects,
- std::queue<u16> &added_objects)
-{
- f32 radius_f = radius * BS;
- f32 player_radius_f = player_radius * BS;
-
- if (player_radius_f < 0)
- player_radius_f = 0;
-
- /*
- Go through the object list,
- - discard m_removed objects,
- - discard objects that are too far away,
- - discard objects that are found in current_objects.
- - add remaining objects to added_objects
- */
- for(std::map<u16, ServerActiveObject*>::iterator
- i = m_active_objects.begin();
- i != m_active_objects.end(); ++i) {
- u16 id = i->first;
-
- // Get object
- ServerActiveObject *object = i->second;
- if(object == NULL)
- continue;
-
- // Discard if removed or deactivating
- if(object->m_removed || object->m_pending_deactivation)
- continue;
-
- f32 distance_f = object->getBasePosition().getDistanceFrom(player->getPosition());
- if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
- // Discard if too far
- if (distance_f > player_radius_f && player_radius_f != 0)
- continue;
- } else if (distance_f > radius_f)
- continue;
-
- // Discard if already on current_objects
- std::set<u16>::iterator n;
- n = current_objects.find(id);
- if(n != current_objects.end())
- continue;
- // Add to added_objects
- added_objects.push(id);
- }
-}
-
-/*
- Finds out what objects have been removed from
- inside a radius around a position
-*/
-void ServerEnvironment::getRemovedActiveObjects(Player *player, s16 radius,
- s16 player_radius,
- std::set<u16> ¤t_objects,
- std::queue<u16> &removed_objects)
-{
- f32 radius_f = radius * BS;
- f32 player_radius_f = player_radius * BS;
-
- if (player_radius_f < 0)
- player_radius_f = 0;
-
- /*
- 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
- - object is too far away
- */
- for(std::set<u16>::iterator
- i = current_objects.begin();
- i != current_objects.end(); ++i)
- {
- u16 id = *i;
- ServerActiveObject *object = getActiveObject(id);
-
- if (object == NULL) {
- infostream << "ServerEnvironment::getRemovedActiveObjects():"
- << " object in current_objects is NULL" << std::endl;
- removed_objects.push(id);
- continue;
- }
-
- if (object->m_removed || object->m_pending_deactivation) {
- removed_objects.push(id);
- continue;
- }
-
- f32 distance_f = object->getBasePosition().getDistanceFrom(player->getPosition());
- if (object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
- if (distance_f <= player_radius_f || player_radius_f == 0)
- continue;
- } else if (distance_f <= radius_f)
- continue;
-
- // Object is no longer visible
- removed_objects.push(id);
- }
-}
-
-void ServerEnvironment::setStaticForActiveObjectsInBlock(
- v3s16 blockpos, bool static_exists, v3s16 static_block)
-{
- MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
- if (!block)
- return;
-
- for (std::map<u16, StaticObject>::iterator
- so_it = block->m_static_objects.m_active.begin();
- so_it != block->m_static_objects.m_active.end(); ++so_it) {
- // Get the ServerActiveObject counterpart to this StaticObject
- std::map<u16, ServerActiveObject *>::iterator ao_it;
- ao_it = m_active_objects.find(so_it->first);
- if (ao_it == m_active_objects.end()) {
- // If this ever happens, there must be some kind of nasty bug.
- errorstream << "ServerEnvironment::setStaticForObjectsInBlock(): "
- "Object from MapBlock::m_static_objects::m_active not found "
- "in m_active_objects";
- continue;
- }
-
- ServerActiveObject *sao = ao_it->second;
- sao->m_static_exists = static_exists;
- sao->m_static_block = static_block;
- }
-}
-
-ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
-{
- if(m_active_object_messages.empty())
- return ActiveObjectMessage(0);
-
- ActiveObjectMessage message = m_active_object_messages.front();
- m_active_object_messages.pop();
- return message;
-}
-
-/*
- ************ Private methods *************
-*/
-
-u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
- bool set_changed, u32 dtime_s)
-{
- assert(object); // Pre-condition
- if(object->getId() == 0){
- u16 new_id = getFreeServerActiveObjectId(m_active_objects);
- if(new_id == 0)
- {
- errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
- <<"no free ids available"<<std::endl;
- if(object->environmentDeletes())
- delete object;
- return 0;
- }
- object->setId(new_id);
- }
- else{
- verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
- <<"supplied with id "<<object->getId()<<std::endl;
- }
- if(isFreeServerActiveObjectId(object->getId(), m_active_objects) == false)
- {
- errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
- <<"id is not free ("<<object->getId()<<")"<<std::endl;
- if(object->environmentDeletes())
- delete object;
- return 0;
- }
-
- if (objectpos_over_limit(object->getBasePosition())) {
- v3f p = object->getBasePosition();
- errorstream << "ServerEnvironment::addActiveObjectRaw(): "
- << "object position (" << p.X << "," << p.Y << "," << p.Z
- << ") outside maximum range" << std::endl;
- if (object->environmentDeletes())
- delete object;
- return 0;
- }
-
- /*infostream<<"ServerEnvironment::addActiveObjectRaw(): "
- <<"added (id="<<object->getId()<<")"<<std::endl;*/
-
- m_active_objects[object->getId()] = object;
-
- verbosestream<<"ServerEnvironment::addActiveObjectRaw(): "
- <<"Added id="<<object->getId()<<"; there are now "
- <<m_active_objects.size()<<" active objects."
- <<std::endl;
-
- // Register reference in scripting api (must be done before post-init)
- m_script->addObjectReference(object);
- // Post-initialize object
- object->addedToEnvironment(dtime_s);
-
- // Add static data to block
- if(object->isStaticAllowed())
- {
- // Add static object to active static list of the block
- v3f objectpos = object->getBasePosition();
- std::string staticdata = object->getStaticData();
- StaticObject s_obj(object->getType(), objectpos, staticdata);
- // Add to the block where the object is located in
- v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
- MapBlock *block = m_map->emergeBlock(blockpos);
- if(block){
- block->m_static_objects.m_active[object->getId()] = s_obj;
- object->m_static_exists = true;
- object->m_static_block = blockpos;
-
- if(set_changed)
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_ADD_ACTIVE_OBJECT_RAW);
- } else {
- v3s16 p = floatToInt(objectpos, BS);
- errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
- <<"could not emerge block for storing id="<<object->getId()
- <<" statically (pos="<<PP(p)<<")"<<std::endl;
- }
- }
-
- return object->getId();
-}
-
-/*
- Remove objects that satisfy (m_removed && m_known_by_count==0)
-*/
-void ServerEnvironment::removeRemovedObjects()
-{
- std::vector<u16> objects_to_remove;
- for(std::map<u16, ServerActiveObject*>::iterator
- i = m_active_objects.begin();
- i != m_active_objects.end(); ++i) {
- u16 id = i->first;
- ServerActiveObject* obj = i->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
- objects_to_remove.push_back(id);
- continue;
- }
-
- /*
- We will delete objects that are marked as removed or thatare
- waiting for deletion after deactivation
- */
- if(obj->m_removed == false && obj->m_pending_deactivation == false)
- continue;
-
- /*
- Delete static data from block if is marked as 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 m_known_by_count > 0, 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
- */
- if(obj->m_static_exists && !obj->m_removed){
- 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()){
- 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 {
- infostream<<"Failed to emerge block from which an object to "
- <<"be deactivated was loaded from. id="<<id<<std::endl;
- }
- }
-
- // Tell the object about removal
- obj->removingFromEnvironment();
- // Deregister in scripting api
- m_script->removeObjectReference(obj);
-
- // Delete
- 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
- for(std::vector<u16>::iterator i = objects_to_remove.begin();
- i != objects_to_remove.end(); ++i) {
- m_active_objects.erase(*i);
- }
-}
-
-static void print_hexdump(std::ostream &o, const std::string &data)
-{
- const int linelength = 16;
- for(int l=0; ; l++){
- int i0 = linelength * l;
- bool at_end = false;
- int thislinelength = linelength;
- if(i0 + thislinelength > (int)data.size()){
- thislinelength = data.size() - i0;
- at_end = true;
- }
- for(int di=0; di<linelength; di++){
- int i = i0 + di;
- char buf[4];
- if(di<thislinelength)
- snprintf(buf, 4, "%.2x ", data[i]);
- else
- snprintf(buf, 4, " ");
- o<<buf;
- }
- o<<" ";
- for(int di=0; di<thislinelength; di++){
- int i = i0 + di;
- if(data[i] >= 32)
- o<<data[i];
- else
- o<<".";
- }
- o<<std::endl;
- if(at_end)
- break;
- }
-}
-
-/*
- Convert stored objects from blocks near the players to active.
-*/
-void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
-{
- if(block == NULL)
- return;
-
- // Ignore if no stored objects (to not set changed flag)
- if(block->m_static_objects.m_stored.empty())
- return;
-
- verbosestream<<"ServerEnvironment::activateObjects(): "
- <<"activating objects of block "<<PP(block->getPos())
- <<" ("<<block->m_static_objects.m_stored.size()
- <<" objects)"<<std::endl;
- bool large_amount = (block->m_static_objects.m_stored.size() > g_settings->getU16("max_objects_per_block"));
- if (large_amount) {
- errorstream<<"suspiciously large amount of objects detected: "
- <<block->m_static_objects.m_stored.size()<<" in "
- <<PP(block->getPos())
- <<"; removing all of them."<<std::endl;
- // Clear stored list
- block->m_static_objects.m_stored.clear();
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- MOD_REASON_TOO_MANY_OBJECTS);
- return;
- }
-
- // Activate stored objects
- std::vector<StaticObject> new_stored;
- for (std::vector<StaticObject>::iterator
- i = block->m_static_objects.m_stored.begin();
- i != block->m_static_objects.m_stored.end(); ++i) {
- StaticObject &s_obj = *i;
-
- // Create an active object from the data
- ServerActiveObject *obj = ServerActiveObject::create
- ((ActiveObjectType) s_obj.type, this, 0, s_obj.pos, s_obj.data);
- // If couldn't create object, store static data back.
- if(obj == NULL) {
- errorstream<<"ServerEnvironment::activateObjects(): "
- <<"failed to create active object from static object "
- <<"in block "<<PP(s_obj.pos/BS)
- <<" type="<<(int)s_obj.type<<" data:"<<std::endl;
- print_hexdump(verbosestream, s_obj.data);
-
- new_stored.push_back(s_obj);
- continue;
- }
- verbosestream<<"ServerEnvironment::activateObjects(): "
- <<"activated static object pos="<<PP(s_obj.pos/BS)
- <<" type="<<(int)s_obj.type<<std::endl;
- // 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
- for(std::vector<StaticObject>::iterator
- i = new_stored.begin();
- i != new_stored.end(); ++i) {
- StaticObject &s_obj = *i;
- block->m_static_objects.m_stored.push_back(s_obj);
- }
-
- // Turn the active counterparts of activated objects not pending for
- // deactivation
- for(std::map<u16, StaticObject>::iterator
- i = block->m_static_objects.m_active.begin();
- i != block->m_static_objects.m_active.end(); ++i)
- {
- 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
- static list to the active static list.
- As such, the block is essentially the same.
- Thus, do not call block->raiseModified(MOD_STATE_WRITE_NEEDED).
- Otherwise there would be a huge amount of unnecessary I/O.
- */
-}
-
-/*
- Convert objects that are not standing inside active blocks to static.
-
- If m_known_by_count != 0, active object is not deleted, but static
- data is still updated.
-
- If force_delete is set, active object is deleted nevertheless. It
- shall only be set so in the destructor of the environment.
-
- If block wasn't generated (not in memory or on disk),
-*/
-void ServerEnvironment::deactivateFarObjects(bool force_delete)
-{
- std::vector<u16> objects_to_remove;
- for(std::map<u16, ServerActiveObject*>::iterator
- i = m_active_objects.begin();
- i != m_active_objects.end(); ++i) {
- ServerActiveObject* obj = i->second;
- assert(obj);
-
- // Do not deactivate if static data creation not allowed
- if(!force_delete && !obj->isStaticAllowed())
- continue;
-
- // If pending deactivation, let removeRemovedObjects() do it
- if(!force_delete && obj->m_pending_deactivation)
- continue;
-
- u16 id = i->first;
- v3f objectpos = obj->getBasePosition();
-
- // The block in which the object resides in
- v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
-
- // If object's static data is stored in a deactivated block and object
- // is actually located in an active block, re-save to the block in
- // which the object is actually located in.
- if(!force_delete &&
- obj->m_static_exists &&
- !m_active_blocks.contains(obj->m_static_block) &&
- m_active_blocks.contains(blockpos_o))
- {
- v3s16 old_static_block = obj->m_static_block;
-
- // 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();
- 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);
-
- // 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(!force_delete && m_active_blocks.contains(blockpos_o))
- continue;
-
- 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
- std::string staticdata_new = obj->getStaticData();
- StaticObject s_obj(obj->getType(), objectpos, staticdata_new);
-
- bool stays_in_same_block = false;
- bool data_changed = true;
-
- if (obj->m_static_exists) {
- if (obj->m_static_block == blockpos_o)
- stays_in_same_block = true;
-
- MapBlock *block = m_map->emergeBlock(obj->m_static_block, false);
-
- if (block) {
- std::map<u16, StaticObject>::iterator n =
- block->m_static_objects.m_active.find(id);
- if (n != block->m_static_objects.m_active.end()) {
- StaticObject static_old = n->second;
-
- float save_movem = obj->getMinimumSavedMovement();
-
- if (static_old.data == staticdata_new &&
- (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;
- }
- }
- }
-
- bool shall_be_written = (!stays_in_same_block || data_changed);
-
- // 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);
- }
- }
-
- // 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")){
- errorstream<<"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.
- Otherwise delete it immediately.
- */
-
- if(pending_delete && !force_delete)
- {
- 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;
-
- // Tell the object about removal
- obj->removingFromEnvironment();
- // Deregister in scripting api
- m_script->removeObjectReference(obj);
-
- // Delete active object
- 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
- for(std::vector<u16>::iterator i = objects_to_remove.begin();
- i != objects_to_remove.end(); ++i) {
- m_active_objects.erase(*i);
- }
-}
-
-#ifndef SERVER
-
-#include "clientsimpleobject.h"
-
-/*
- ClientEnvironment
-*/
-
-ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr,
- ITextureSource *texturesource, IGameDef *gamedef,
- IrrlichtDevice *irr):
- m_map(map),
- m_smgr(smgr),
- m_texturesource(texturesource),
- m_gamedef(gamedef),
- m_irr(irr)
-{
- char zero = 0;
- memset(attachement_parent_ids, zero, sizeof(attachement_parent_ids));
-}
-
-ClientEnvironment::~ClientEnvironment()
-{
- // delete active objects
- for(std::map<u16, ClientActiveObject*>::iterator
- i = m_active_objects.begin();
- i != m_active_objects.end(); ++i)
- {
- delete i->second;
- }
-
- for(std::vector<ClientSimpleObject*>::iterator
- i = m_simple_objects.begin(); i != m_simple_objects.end(); ++i) {
- delete *i;
- }
-
- // Drop/delete map
- m_map->drop();
-}
-
-Map & ClientEnvironment::getMap()