-
-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()){
- infostream<<"ServerEnv: WARNING: 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()
-{
- return *m_map;
-}
-
-ClientMap & ClientEnvironment::getClientMap()
-{
- return *m_map;
-}
-
-void ClientEnvironment::addPlayer(Player *player)
-{
- DSTACK(__FUNCTION_NAME);
- /*
- It is a failure if player is local and there already is a local
- player
- */
- FATAL_ERROR_IF(player->isLocal() == true && getLocalPlayer() != NULL,
- "Player is local but there is already a local player");
-
- Environment::addPlayer(player);
-}
-
-LocalPlayer * ClientEnvironment::getLocalPlayer()
-{
- for(std::vector<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);
-
- /* Step time of day */
- stepTimeOfDay(dtime);
-
- // Get some settings
- bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
- bool free_move = fly_allowed && g_settings->getBool("free_move");
-
- // Get local player
- LocalPlayer *lplayer = getLocalPlayer();
- assert(lplayer);
- // collision info queue
- std::vector<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
- */
-
- {
- // Apply physics
- if(free_move == false && is_climbing == false)
- {
- // Gravity
- v3f speed = lplayer->getSpeed();
- if(lplayer->in_liquid == false)
- speed.Y -= lplayer->movement_gravity * lplayer->physics_override_gravity * dtime_part * 2;
-
- // Liquid floating / sinking
- if(lplayer->in_liquid && !lplayer->swimming_vertical)
- speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2;
-
- // Liquid resistance
- if(lplayer->in_liquid_stable || lplayer->in_liquid)
- {
- // How much the node's viscosity blocks movement, ranges between 0 and 1
- // Should match the scale at which viscosity increase affects other liquid attributes
- const f32 viscosity_factor = 0.3;
-
- v3f d_wanted = -speed / lplayer->movement_liquid_fluidity;
- f32 dl = d_wanted.getLength();
- if(dl > lplayer->movement_liquid_fluidity_smooth)
- dl = lplayer->movement_liquid_fluidity_smooth;
- dl *= (lplayer->liquid_viscosity * viscosity_factor) + (1 - viscosity_factor);
-
- v3f d = d_wanted.normalize() * dl;
- speed += d;
- }
-
- lplayer->setSpeed(speed);
- }
-
- /*
- Move the lplayer.
- This also does collision detection.
- */
- lplayer->move(dtime_part, this, position_max_increment,
- &player_collisions);
- }
- }
- while(dtime_downcount > 0.001);
-
- //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
-
- for(std::vector<CollisionInfo>::iterator i = player_collisions.begin();
- i != player_collisions.end(); ++i) {
- CollisionInfo &info = *i;
- v3f speed_diff = info.new_speed - info.old_speed;;
- // Handle only fall damage
- // (because otherwise walking against something in fast_move kills you)
- if(speed_diff.Y < 0 || info.old_speed.Y >= 0)
- continue;
- // Get rid of other components
- speed_diff.X = 0;
- speed_diff.Z = 0;
- f32 pre_factor = 1; // 1 hp per node/s
- f32 tolerance = BS*14; // 5 without damage
- f32 post_factor = 1; // 1 hp per node/s
- if(info.type == COLLISION_NODE)
- {
- const ContentFeatures &f = m_gamedef->ndef()->
- get(m_map->getNodeNoEx(info.node_p));
- // Determine fall damage multiplier
- int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
- pre_factor = 1.0 + (float)addp/100.0;
- }
- float speed = pre_factor * speed_diff.getLength();
- if(speed > tolerance)
- {
- f32 damage_f = (speed - tolerance)/BS * post_factor;
- u16 damage = (u16)(damage_f+0.5);
- if(damage != 0){
- damageLocalPlayer(damage, true);
- MtEvent *e = new SimpleTriggerEvent("PlayerFallingDamage");
- m_gamedef->event()->put(e);
- }
- }
- }
-
- /*
- A quick draft of lava damage
- */
- if(m_lava_hurt_interval.step(dtime, 1.0))
- {
- v3f pf = lplayer->getPosition();
-
- // Feet, middle and head
- v3s16 p1 = floatToInt(pf + v3f(0, BS*0.1, 0), BS);
- MapNode n1 = m_map->getNodeNoEx(p1);
- v3s16 p2 = floatToInt(pf + v3f(0, BS*0.8, 0), BS);
- MapNode n2 = m_map->getNodeNoEx(p2);
- v3s16 p3 = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
- MapNode n3 = m_map->getNodeNoEx(p3);
-
- u32 damage_per_second = 0;
- damage_per_second = MYMAX(damage_per_second,
- m_gamedef->ndef()->get(n1).damage_per_second);
- damage_per_second = MYMAX(damage_per_second,
- m_gamedef->ndef()->get(n2).damage_per_second);
- damage_per_second = MYMAX(damage_per_second,
- m_gamedef->ndef()->get(n3).damage_per_second);
-
- if(damage_per_second != 0)
- {
- damageLocalPlayer(damage_per_second, true);
- }
- }
-
- /*
- Drowning
- */
- if(m_drowning_interval.step(dtime, 2.0))
- {
- v3f pf = lplayer->getPosition();
-
- // head
- v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
- MapNode n = m_map->getNodeNoEx(p);
- ContentFeatures c = m_gamedef->ndef()->get(n);
- u8 drowning_damage = c.drowning;
- if(drowning_damage > 0 && lplayer->hp > 0){
- u16 breath = lplayer->getBreath();
- if(breath > 10){
- breath = 11;
- }
- if(breath > 0){
- breath -= 1;
- }
- lplayer->setBreath(breath);
- updateLocalPlayerBreath(breath);
- }
-
- if(lplayer->getBreath() == 0 && drowning_damage > 0){
- damageLocalPlayer(drowning_damage, true);
- }
- }
- if(m_breathing_interval.step(dtime, 0.5))
- {
- v3f pf = lplayer->getPosition();
-
- // head
- v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS);
- MapNode n = m_map->getNodeNoEx(p);
- ContentFeatures c = m_gamedef->ndef()->get(n);
- if (!lplayer->hp){
- lplayer->setBreath(11);
- }
- else if(c.drowning == 0){
- u16 breath = lplayer->getBreath();
- if(breath <= 10){
- breath += 1;
- lplayer->setBreath(breath);
- updateLocalPlayerBreath(breath);
- }
- }
- }
-
- /*
- Stuff that can be done in an arbitarily large dtime
- */
- for(std::vector<Player*>::iterator i = m_players.begin();
- i != m_players.end(); ++i) {
- Player *player = *i;
-
- /*
- Handle non-local players
- */
- if(player->isLocal() == false) {
- // Move
- player->move(dtime, this, 100*BS);
-
- }
- }
-
- // Update lighting on local player (used for wield item)
- u32 day_night_ratio = getDayNightRatio();
- {
- // Get node at head
-
- // On InvalidPositionException, use this as default
- // (day: LIGHT_SUN, night: 0)
- MapNode node_at_lplayer(CONTENT_AIR, 0x0f, 0);
-
- v3s16 p = lplayer->getLightPosition();
- node_at_lplayer = m_map->getNodeNoEx(p);
-
- u16 light = getInteriorLight(node_at_lplayer, 0, m_gamedef->ndef());
- u8 day = light & 0xff;
- u8 night = (light >> 8) & 0xff;
- finalColorBlend(lplayer->light_color, day, night, day_night_ratio);
- }
-
- /*
- Step active objects and update lighting of them
- */
-
- g_profiler->avg("CEnv: num of objects", m_active_objects.size());
- bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21);
- for(std::map<u16, ClientActiveObject*>::iterator
- i = m_active_objects.begin();
- i != m_active_objects.end(); ++i)
- {
- ClientActiveObject* obj = i->second;
- // Step object
- obj->step(dtime, this);
-
- if(update_lighting)
- {
- // Update lighting
- u8 light = 0;
- bool pos_ok;
-
- // Get node at head
- v3s16 p = obj->getLightPosition();
- MapNode n = m_map->getNodeNoEx(p, &pos_ok);
- if (pos_ok)
- light = n.getLightBlend(day_night_ratio, m_gamedef->ndef());
- else
- light = blend_light(day_night_ratio, LIGHT_SUN, 0);
-
- obj->updateLight(light);
- }
- }
-
- /*
- Step and handle simple objects
- */
- g_profiler->avg("CEnv: num of simple objects", m_simple_objects.size());
- for(std::vector<ClientSimpleObject*>::iterator
- i = m_simple_objects.begin(); i != m_simple_objects.end();) {
- std::vector<ClientSimpleObject*>::iterator cur = i;
- ClientSimpleObject *simple = *cur;
-
- simple->step(dtime);
- if(simple->m_to_be_removed) {
- delete simple;
- i = m_simple_objects.erase(cur);
- }
- else {
- ++i;
- }
- }
-}
-
-void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)
-{
- m_simple_objects.push_back(simple);
-}
-
-GenericCAO* ClientEnvironment::getGenericCAO(u16 id)
-{
- ClientActiveObject *obj = getActiveObject(id);
- if (obj && obj->getType() == ACTIVEOBJECT_TYPE_GENERIC)
- return (GenericCAO*) obj;
- else
- return NULL;
-}
-
-ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
-{
- std::map<u16, ClientActiveObject*>::iterator n;
- n = m_active_objects.find(id);
- if(n == m_active_objects.end())
- return NULL;
- return n->second;
-}
-
-bool isFreeClientActiveObjectId(u16 id,
- std::map<u16, ClientActiveObject*> &objects)
-{
- if(id == 0)
- return false;
-
- return objects.find(id) == objects.end();
-}
-
-u16 getFreeClientActiveObjectId(
- std::map<u16, ClientActiveObject*> &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(isFreeClientActiveObjectId(last_used_id, objects))
- return last_used_id;
-
- if(last_used_id == startid)
- return 0;
- }
-}
-
-u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
-{
- assert(object); // Pre-condition
- if(object->getId() == 0)
- {
- u16 new_id = getFreeClientActiveObjectId(m_active_objects);
- if(new_id == 0)
- {
- infostream<<"ClientEnvironment::addActiveObject(): "
- <<"no free ids available"<<std::endl;
- delete object;
- return 0;
- }
- object->setId(new_id);
- }
- if(isFreeClientActiveObjectId(object->getId(), m_active_objects) == false)
- {
- infostream<<"ClientEnvironment::addActiveObject(): "
- <<"id is not free ("<<object->getId()<<")"<<std::endl;
- delete object;
- return 0;
- }
- infostream<<"ClientEnvironment::addActiveObject(): "
- <<"added (id="<<object->getId()<<")"<<std::endl;
- m_active_objects[object->getId()] = object;
- object->addToScene(m_smgr, m_texturesource, m_irr);
- { // Update lighting immediately
- u8 light = 0;
- bool pos_ok;
-
- // Get node at head
- v3s16 p = object->getLightPosition();
- MapNode n = m_map->getNodeNoEx(p, &pos_ok);
- if (pos_ok)
- light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
- else
- light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
-
- object->updateLight(light);
- }
- return object->getId();
-}
-
-void ClientEnvironment::addActiveObject(u16 id, u8 type,
- const std::string &init_data)
-{
- ClientActiveObject* obj =
- ClientActiveObject::create((ActiveObjectType) type, m_gamedef, this);
- if(obj == NULL)
- {
- infostream<<"ClientEnvironment::addActiveObject(): "
- <<"id="<<id<<" type="<<type<<": Couldn't create object"
- <<std::endl;
- return;
- }
-
- obj->setId(id);
-
- try
- {
- obj->initialize(init_data);
- }
- catch(SerializationError &e)
- {
- errorstream<<"ClientEnvironment::addActiveObject():"
- <<" id="<<id<<" type="<<type
- <<": SerializationError in initialize(): "
- <<e.what()
- <<": init_data="<<serializeJsonString(init_data)
- <<std::endl;
- }
-
- addActiveObject(obj);
-}
-
-void ClientEnvironment::removeActiveObject(u16 id)
-{
- verbosestream<<"ClientEnvironment::removeActiveObject(): "
- <<"id="<<id<<std::endl;
- ClientActiveObject* obj = getActiveObject(id);
- if(obj == NULL)
- {
- infostream<<"ClientEnvironment::removeActiveObject(): "
- <<"id="<<id<<" not found"<<std::endl;
- return;
- }
- obj->removeFromScene(true);
- delete obj;
- m_active_objects.erase(id);
-}
-
-void ClientEnvironment::processActiveObjectMessage(u16 id, const std::string &data)
-{
- ClientActiveObject *obj = getActiveObject(id);
- if (obj == NULL) {
- infostream << "ClientEnvironment::processActiveObjectMessage():"
- << " got message for id=" << id << ", which doesn't exist."
- << std::endl;
- return;
- }
-
- try {
- obj->processMessage(data);
- } catch (SerializationError &e) {
- errorstream<<"ClientEnvironment::processActiveObjectMessage():"
- << " id=" << id << " type=" << obj->getType()
- << " SerializationError in processMessage(): " << e.what()
- << std::endl;
- }
-}
-
-/*
- Callbacks for activeobjects
-*/
-
-void ClientEnvironment::damageLocalPlayer(u8 damage, bool handle_hp)
-{
- LocalPlayer *lplayer = getLocalPlayer();
- assert(lplayer);
-
- if (handle_hp) {
- if (lplayer->hp > damage)
- lplayer->hp -= damage;
- else
- lplayer->hp = 0;
- }
-
- ClientEnvEvent event;
- event.type = CEE_PLAYER_DAMAGE;
- event.player_damage.amount = damage;
- event.player_damage.send_to_server = handle_hp;
- m_client_event_queue.push(event);
-}
-
-void ClientEnvironment::updateLocalPlayerBreath(u16 breath)
-{
- ClientEnvEvent event;
- event.type = CEE_PLAYER_BREATH;
- event.player_breath.amount = breath;
- m_client_event_queue.push(event);
-}
-
-/*
- Client likes to call these
-*/
-
-void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
- std::vector<DistanceSortedActiveObject> &dest)
-{
- for(std::map<u16, ClientActiveObject*>::iterator
- i = m_active_objects.begin();
- i != m_active_objects.end(); ++i)
- {
- ClientActiveObject* obj = i->second;
-
- f32 d = (obj->getPosition() - origin).getLength();
-
- if(d > max_d)
- continue;
-
- DistanceSortedActiveObject dso(obj, d);
-
- dest.push_back(dso);
- }
-}
-
-ClientEnvEvent ClientEnvironment::getClientEvent()
-{
- ClientEnvEvent event;
- if(m_client_event_queue.empty())
- event.type = CEE_NONE;
- else {
- event = m_client_event_queue.front();
- m_client_event_queue.pop();
- }
- return event;
-}
-
-#endif // #ifndef SERVER
-
-