- }
- removed_objects.insert(id, false);
- }
-}
-
-ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
-{
- if(m_active_object_messages.size() == 0)
- return ActiveObjectMessage(0);
-
- return m_active_object_messages.pop_front();
-}
-
-/*
- ************ Private methods *************
-*/
-
-u16 ServerEnvironment::addActiveObjectRaw(ServerActiveObject *object,
- bool set_changed)
-{
- assert(object);
- 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;
- }
- /*infostream<<"ServerEnvironment::addActiveObjectRaw(): "
- <<"added (id="<<object->getId()<<")"<<std::endl;*/
-
- m_active_objects.insert(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)
- scriptapi_add_object_reference(m_lua, object);
- // Post-initialize object
- object->addedToEnvironment();
-
- // 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->getBlockNoCreateNoEx(blockpos);
- if(block)
- {
- block->m_static_objects.m_active.insert(object->getId(), s_obj);
- object->m_static_exists = true;
- object->m_static_block = blockpos;
-
- if(set_changed)
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- "addActiveObjectRaw");
- }
- else{
- errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
- <<"could not find block for storing id="<<object->getId()
- <<" statically"<<std::endl;
- }
- }
-
- return object->getId();
-}
-
-/*
- Remove objects that satisfy (m_removed && m_known_by_count==0)
-*/
-void ServerEnvironment::removeRemovedObjects()
-{
- core::list<u16> objects_to_remove;
- for(core::map<u16, ServerActiveObject*>::Iterator
- i = m_active_objects.getIterator();
- i.atEnd()==false; i++)
- {
- u16 id = i.getNode()->getKey();
- ServerActiveObject* obj = i.getNode()->getValue();
- // 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);
- if(block)
- {
- block->m_static_objects.remove(id);
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- "removeRemovedObjects");
- obj->m_static_exists = false;
- }
- }
-
- // If m_known_by_count > 0, don't actually remove.
- if(obj->m_known_by_count > 0)
- continue;
-
- // Tell the object about removal
- obj->removingFromEnvironment();
- // Deregister in scripting api
- scriptapi_rm_object_reference(m_lua, 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(core::list<u16>::Iterator i = objects_to_remove.begin();
- i != objects_to_remove.end(); i++)
- {
- m_active_objects.remove(*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)
-{
- if(block==NULL)
- return;
- // Ignore if no stored objects (to not set changed flag)
- if(block->m_static_objects.m_stored.size() == 0)
- 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() > 49);
- 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,
- "stored list cleared in activateObjects due to "
- "large amount of objects");
- return;
- }
- // A list for objects that couldn't be converted to static for some
- // reason. They will be stored back.
- core::list<StaticObject> new_stored;
- // Loop through stored static objects
- for(core::list<StaticObject>::Iterator
- i = block->m_static_objects.m_stored.begin();
- i != block->m_static_objects.m_stored.end(); i++)
- {
- /*infostream<<"Server: Creating an active object from "
- <<"static data"<<std::endl;*/
- StaticObject &s_obj = *i;
- // Create an active object from the data
- ServerActiveObject *obj = ServerActiveObject::create
- (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);
- }
- // Clear stored list
- block->m_static_objects.m_stored.clear();
- // Add leftover failed stuff to stored list
- for(core::list<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);
- }
- /*
- 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.
-*/
-void ServerEnvironment::deactivateFarObjects(bool force_delete)
-{
- core::list<u16> objects_to_remove;
- for(core::map<u16, ServerActiveObject*>::Iterator
- i = m_active_objects.getIterator();
- i.atEnd()==false; i++)
- {
- ServerActiveObject* obj = i.getNode()->getValue();
- 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.getNode()->getKey();
- v3f objectpos = obj->getBasePosition();
-
- // The block in which the object resides in
- v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
-
- // 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);
-
- core::map<u16, StaticObject>::Node *n =
- block->m_static_objects.m_active.find(id);
- if(n){
- StaticObject static_old = n->getValue();
-
- 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,
- "deactivateFarObjects: Static data "
- "changed considerably");
- }
- }
-
- // Add to the block where the object is located in
- v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS));
- // Get or generate the block
- MapBlock *block = m_map->emergeBlock(blockpos);
-
- if(block)
- {
- if(block->m_static_objects.m_stored.size() >= 49){
- errorstream<<"ServerEnv: Trying to store id="<<obj->getId()
- <<" statically but block "<<PP(blockpos)
- <<" already contains "
- <<block->m_static_objects.m_stored.size()
- <<" (over 49) objects."
- <<" Forcing delete."<<std::endl;
- force_delete = true;
- } else {
- u16 new_id = pending_delete ? id : 0;
- block->m_static_objects.insert(new_id, s_obj);
-
- // Only mark block as modified if data changed considerably
- if(shall_be_written)
- block->raiseModified(MOD_STATE_WRITE_NEEDED,
- "deactivateFarObjects: Static data "
- "changed considerably");
-
- obj->m_static_exists = true;
- obj->m_static_block = block->getPos();
- }
- }
- else{
- if(!force_delete){
- errorstream<<"ServerEnv: Could not find or generate "
- <<"a block for storing id="<<obj->getId()
- <<" statically"<<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
- scriptapi_rm_object_reference(m_lua, 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(core::list<u16>::Iterator i = objects_to_remove.begin();
- i != objects_to_remove.end(); i++)
- {
- m_active_objects.remove(*i);
- }
-}
-
-
-#ifndef SERVER
-
-/*
- 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)
-{
-}
-
-ClientEnvironment::~ClientEnvironment()
-{
- // delete active objects
- for(core::map<u16, ClientActiveObject*>::Iterator
- i = m_active_objects.getIterator();
- i.atEnd()==false; i++)
- {
- delete i.getNode()->getValue();
- }
-
- // Drop/delete map
- m_map->drop();
-}
-
-void ClientEnvironment::addPlayer(Player *player)
-{
- DSTACK(__FUNCTION_NAME);
- /*
- It is a failure if player is local and there already is a local
- player
- */
- assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
-
- Environment::addPlayer(player);
-}
-
-LocalPlayer * ClientEnvironment::getLocalPlayer()
-{
- for(core::list<Player*>::Iterator i = m_players.begin();
- i != m_players.end(); i++)
- {
- Player *player = *i;
- if(player->isLocal())
- return (LocalPlayer*)player;
- }
- return NULL;
-}
-
-void ClientEnvironment::step(float dtime)
-{
- DSTACK(__FUNCTION_NAME);
-
- // Get some settings
- bool free_move = g_settings->getBool("free_move");
- bool footprints = g_settings->getBool("footprints");
-
- // Get local player
- LocalPlayer *lplayer = getLocalPlayer();
- assert(lplayer);
- // collision info queue
- core::list<CollisionInfo> player_collisions;
-
- /*
- Get the speed the player is going
- */
- bool is_climbing = lplayer->is_climbing;
-
- f32 player_speed = lplayer->getSpeed().getLength();
-
- /*
- Maximum position increment
- */
- //f32 position_max_increment = 0.05*BS;
- f32 position_max_increment = 0.1*BS;
-
- // Maximum time increment (for collision detection etc)
- // time = distance / speed
- f32 dtime_max_increment = 1;
- if(player_speed > 0.001)
- dtime_max_increment = position_max_increment / player_speed;
-
- // Maximum time increment is 10ms or lower
- if(dtime_max_increment > 0.01)
- dtime_max_increment = 0.01;
-
- // Don't allow overly huge dtime
- if(dtime > 0.5)
- dtime = 0.5;
-
- f32 dtime_downcount = dtime;
-
- /*
- Stuff that has a maximum time increment
- */
-
- u32 loopcount = 0;
- do
- {
- loopcount++;
-
- f32 dtime_part;
- if(dtime_downcount > dtime_max_increment)
- {
- dtime_part = dtime_max_increment;
- dtime_downcount -= dtime_part;
- }
- else
- {
- dtime_part = dtime_downcount;
- /*
- Setting this to 0 (no -=dtime_part) disables an infinite loop
- when dtime_part is so small that dtime_downcount -= dtime_part
- does nothing
- */
- dtime_downcount = 0;
- }
-
- /*
- Handle local player
- */
-
- {
- v3f lplayerpos = lplayer->getPosition();
-
- // Apply physics
- if(free_move == false && is_climbing == false)
- {
- // Gravity
- v3f speed = lplayer->getSpeed();
- if(lplayer->swimming_up == false)
- speed.Y -= 9.81 * BS * dtime_part * 2;
-
- // Water resistance
- if(lplayer->in_water_stable || lplayer->in_water)
- {
- f32 max_down = 2.0*BS;
- if(speed.Y < -max_down) speed.Y = -max_down;
-
- f32 max = 2.5*BS;
- if(speed.getLength() > max)
- {
- speed = speed / speed.getLength() * max;
- }
- }
-
- lplayer->setSpeed(speed);
- }
-
- /*
- Move the lplayer.
- This also does collision detection.
- */
- lplayer->move(dtime_part, *m_map, position_max_increment,
- &player_collisions);
- }
- }
- while(dtime_downcount > 0.001);
-
- //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
-
- for(core::list<CollisionInfo>::Iterator
- i = player_collisions.begin();
- i != player_collisions.end(); i++)
- {
- CollisionInfo &info = *i;
- if(info.t == COLLISION_FALL)
- {
- //f32 tolerance = BS*10; // 2 without damage
- f32 tolerance = BS*12; // 3 without damage
- f32 factor = 1;
- if(info.speed > tolerance)
- {
- f32 damage_f = (info.speed - tolerance)/BS*factor;
- u16 damage = (u16)(damage_f+0.5);
- if(lplayer->hp > damage)
- lplayer->hp -= damage;
- else
- lplayer->hp = 0;
-
- ClientEnvEvent event;
- event.type = CEE_PLAYER_DAMAGE;
- event.player_damage.amount = damage;
- m_client_event_queue.push_back(event);