-
-u16 getFreeServerActiveObjectId(
- core::map<u16, ServerActiveObject*> &objects)
-{
- u16 new_id = 1;
- for(;;)
- {
- if(isFreeServerActiveObjectId(new_id, objects))
- return new_id;
-
- if(new_id == 65535)
- return 0;
-
- new_id++;
- }
-}
-
-u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
-{
- assert(object);
- u16 id = addActiveObjectRaw(object, true, 0);
- return id;
-}
-
-bool ServerEnvironment::addActiveObjectAsStatic(ServerActiveObject *obj)
-{
- assert(obj);
-
- v3f objectpos = obj->getBasePosition();
-
- // The block in which the object resides in
- v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS));
-
- /*
- Update the static data
- */
-
- // Create new static object
- std::string staticdata = obj->getStaticData();
- StaticObject s_obj(obj->getType(), objectpos, staticdata);
- // 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);
-
- bool succeeded = false;
-
- if(block)
- {
- block->m_static_objects.insert(0, s_obj);
- block->raiseModified(MOD_STATE_WRITE_AT_UNLOAD,
- "addActiveObjectAsStatic");
- succeeded = true;
- }
- else{
- infostream<<"ServerEnvironment::addActiveObjectAsStatic: "
- <<"Could not find or generate "
- <<"a block for storing static object"<<std::endl;
- succeeded = false;
- }
-
- if(obj->environmentDeletes())
- delete obj;
-
- return succeeded;
-}
-
-/*
- Finds out what new objects have been added to
- inside a radius around a position
-*/
-void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
- core::map<u16, bool> ¤t_objects,
- core::map<u16, bool> &added_objects)
-{
- v3f pos_f = intToFloat(pos, BS);
- f32 radius_f = radius * BS;
- /*
- 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(core::map<u16, ServerActiveObject*>::Iterator
- i = m_active_objects.getIterator();
- i.atEnd()==false; i++)
- {
- u16 id = i.getNode()->getKey();
- // Get object
- ServerActiveObject *object = i.getNode()->getValue();
- if(object == NULL)
- continue;
- // Discard if removed
- if(object->m_removed)
- continue;
- if(object->unlimitedTransferDistance() == false){
- // Discard if too far
- f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
- if(distance_f > radius_f)
- continue;
- }
- // Discard if already on current_objects
- core::map<u16, bool>::Node *n;
- n = current_objects.find(id);
- if(n != NULL)
- continue;
- // Add to added_objects
- added_objects.insert(id, false);
- }
-}
-
-/*
- Finds out what objects have been removed from
- inside a radius around a position
-*/
-void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
- core::map<u16, bool> ¤t_objects,
- core::map<u16, bool> &removed_objects)
-{
- v3f pos_f = intToFloat(pos, BS);
- f32 radius_f = radius * BS;
- /*
- 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(core::map<u16, bool>::Iterator
- i = current_objects.getIterator();
- i.atEnd()==false; i++)
- {
- u16 id = i.getNode()->getKey();
- ServerActiveObject *object = getActiveObject(id);
-
- if(object == NULL){
- infostream<<"ServerEnvironment::getRemovedActiveObjects():"
- <<" object in current_objects is NULL"<<std::endl;
- removed_objects.insert(id, false);
- continue;
- }
-
- if(object->m_removed)
- {
- removed_objects.insert(id, false);
- continue;
- }
-
- // If transfer distance is unlimited, don't remove
- if(object->unlimitedTransferDistance())
- continue;
-
- f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
-
- if(distance_f >= radius_f)
- {
- removed_objects.insert(id, false);
- continue;
- }
-
- // Not removed
- }
-}
-
-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, u32 dtime_s)
-{
- 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(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->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{
- v3s16 p = floatToInt(objectpos, BS);
- errorstream<<"ServerEnvironment::addActiveObjectRaw(): "
- <<"could not find 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()
-{
- 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, u32 dtime_s)
-{
- 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 active 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, dtime_s);
- }
- // 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 = NULL;
- try{
- block = m_map->emergeBlock(blockpos);
- } catch(InvalidPositionException &e){
- // Handled via NULL pointer
- }
-
- 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;
- // If static counterpart already exists, remove it first.
- // This shouldn't happen, but happens rarely for some
- // unknown reason. Unsuccessful attempts have been made to
- // find said reason.
- if(new_id && block->m_static_objects.m_active.find(new_id)){
- infostream<<"ServerEnv: WARNING: Performing hack #83274"
- <<std::endl;
- block->m_static_objects.remove(new_id);
- }
- 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){
- 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
- 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
-
-#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)
-{
-}
-
-ClientEnvironment::~ClientEnvironment()
-{
- // delete active objects
- for(core::map<u16, ClientActiveObject*>::Iterator
- i = m_active_objects.getIterator();
- i.atEnd()==false; i++)
- {
- delete i.getNode()->getValue();
- }
-
- for(core::list<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
- */
- 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);
-
- /* 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
- 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;
- 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);
- }
- }
-
- /*
- 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(p2);
-
- 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);
- }
- }
-
- /*
- Stuff that can be done in an arbitarily large dtime
- */
- for(core::list<Player*>::Iterator i = m_players.begin();
- i != m_players.end(); i++)
- {
- Player *player = *i;
- v3f playerpos = player->getPosition();
-
- /*
- Handle non-local players
- */
- if(player->isLocal() == false)
- {
- // Move
- player->move(dtime, *m_map, 100*BS);
-
- }
-
- // Update lighting on all players on client
- float light = 1.0;
- try{
- // Get node at head
- v3s16 p = player->getLightPosition();
- MapNode n = m_map->getNode(p);
- light = n.getLightBlendF1((float)getDayNightRatio()/1000, m_gamedef->ndef());
- }
- catch(InvalidPositionException &e){
- light = blend_light_f1((float)getDayNightRatio()/1000, LIGHT_SUN, 0);
- }
- player->light = light;
- }
-
- /*
- Step active objects and update lighting of them
- */
-
- bool update_lighting = m_active_object_light_update_interval.step(dtime, 0.21);
- for(core::map<u16, ClientActiveObject*>::Iterator
- i = m_active_objects.getIterator();
- i.atEnd()==false; i++)
- {
- ClientActiveObject* obj = i.getNode()->getValue();
- // Step object
- obj->step(dtime, this);
-
- if(update_lighting)
- {
- // Update lighting
- u8 light = 0;
- try{
- // Get node at head
- v3s16 p = obj->getLightPosition();
- MapNode n = m_map->getNode(p);
- light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
- }
- catch(InvalidPositionException &e){
- light = blend_light(getDayNightRatio(), LIGHT_SUN, 0);
- }
- obj->updateLight(light);
- }
- }
-
- /*
- Step and handle simple objects
- */
- for(core::list<ClientSimpleObject*>::Iterator
- i = m_simple_objects.begin(); i != m_simple_objects.end();)
- {
- ClientSimpleObject *simple = *i;
- core::list<ClientSimpleObject*>::Iterator cur = i;
- i++;
- simple->step(dtime);
- if(simple->m_to_be_removed){
- delete simple;
- m_simple_objects.erase(cur);
- }
- }
-}
-
-void ClientEnvironment::addSimpleObject(ClientSimpleObject *simple)
-{
- m_simple_objects.push_back(simple);
-}
-
-ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
-{
- core::map<u16, ClientActiveObject*>::Node *n;
- n = m_active_objects.find(id);
- if(n == NULL)
- return NULL;
- return n->getValue();
-}
-
-bool isFreeClientActiveObjectId(u16 id,
- core::map<u16, ClientActiveObject*> &objects)
-{
- if(id == 0)
- return false;
-
- for(core::map<u16, ClientActiveObject*>::Iterator
- i = objects.getIterator();
- i.atEnd()==false; i++)
- {
- if(i.getNode()->getKey() == id)
- return false;
- }
- return true;
-}
-
-u16 getFreeClientActiveObjectId(
- core::map<u16, ClientActiveObject*> &objects)
-{
- u16 new_id = 1;
- for(;;)
- {
- if(isFreeClientActiveObjectId(new_id, objects))
- return new_id;
-
- if(new_id == 65535)
- return 0;
-
- new_id++;
- }
-}
-
-u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
-{
- assert(object);
- 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.insert(object->getId(), object);
- object->addToScene(m_smgr, m_texturesource, m_irr);
- { // Update lighting immediately
- u8 light = 0;
- try{
- // Get node at head
- v3s16 p = object->getLightPosition();
- MapNode n = m_map->getNode(p);
- light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef());
- }
- catch(InvalidPositionException &e){
- 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(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.remove(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(),"
- <<" message="<<serializeJsonString(data)
- <<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_back(event);
-}
-
-/*
- Client likes to call these
-*/
-
-void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d,
- core::array<DistanceSortedActiveObject> &dest)
-{
- for(core::map<u16, ClientActiveObject*>::Iterator
- i = m_active_objects.getIterator();
- i.atEnd()==false; i++)
- {
- ClientActiveObject* obj = i.getNode()->getValue();
-
- f32 d = (obj->getPosition() - origin).getLength();
-
- if(d > max_d)
- continue;
-
- DistanceSortedActiveObject dso(obj, d);
-
- dest.push_back(dso);
- }
-}
-
-ClientEnvEvent ClientEnvironment::getClientEvent()
-{
- if(m_client_event_queue.size() == 0)
- {
- ClientEnvEvent event;
- event.type = CEE_NONE;
- return event;
- }
- return m_client_event_queue.pop_front();
-}
-
-#endif // #ifndef SERVER
-
-