LCOV - code coverage report
Current view: top level - src - content_cao.cpp (source / functions) Hit Total Coverage
Test: report Lines: 502 982 51.1 %
Date: 2015-07-11 18:23:49 Functions: 34 71 47.9 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
       4             : 
       5             : This program is free software; you can redistribute it and/or modify
       6             : it under the terms of the GNU Lesser General Public License as published by
       7             : the Free Software Foundation; either version 2.1 of the License, or
       8             : (at your option) any later version.
       9             : 
      10             : This program is distributed in the hope that it will be useful,
      11             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             : GNU Lesser General Public License for more details.
      14             : 
      15             : You should have received a copy of the GNU Lesser General Public License along
      16             : with this program; if not, write to the Free Software Foundation, Inc.,
      17             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             : */
      19             : 
      20             : #include <ICameraSceneNode.h>
      21             : #include <ITextSceneNode.h>
      22             : #include <IBillboardSceneNode.h>
      23             : #include <IMeshManipulator.h>
      24             : #include <IAnimatedMeshSceneNode.h>
      25             : #include <IBoneSceneNode.h>
      26             : #include "content_cao.h"
      27             : #include "util/numeric.h" // For IntervalLimiter
      28             : #include "util/serialize.h"
      29             : #include "util/mathconstants.h"
      30             : #include "client/tile.h"
      31             : #include "environment.h"
      32             : #include "collision.h"
      33             : #include "settings.h"
      34             : #include "serialization.h" // For decompressZlib
      35             : #include "gamedef.h"
      36             : #include "clientobject.h"
      37             : #include "mesh.h"
      38             : #include "itemdef.h"
      39             : #include "tool.h"
      40             : #include "content_cso.h"
      41             : #include "sound.h"
      42             : #include "nodedef.h"
      43             : #include "localplayer.h"
      44             : #include "map.h"
      45             : #include "camera.h" // CameraModes
      46             : #include "wieldmesh.h"
      47             : #include "log.h"
      48             : 
      49             : class Settings;
      50             : struct ToolCapabilities;
      51             : 
      52             : #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
      53             : 
      54           1 : std::map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
      55             : 
      56          45 : SmoothTranslator::SmoothTranslator():
      57             :         vect_old(0,0,0),
      58             :         vect_show(0,0,0),
      59             :         vect_aim(0,0,0),
      60             :         anim_counter(0),
      61             :         anim_time(0),
      62             :         anim_time_counter(0),
      63          45 :         aim_is_end(true)
      64          45 : {}
      65             : 
      66          49 : void SmoothTranslator::init(v3f vect)
      67             : {
      68          49 :         vect_old = vect;
      69          49 :         vect_show = vect;
      70          49 :         vect_aim = vect;
      71          49 :         anim_counter = 0;
      72          49 :         anim_time = 0;
      73          49 :         anim_time_counter = 0;
      74          49 :         aim_is_end = true;
      75          49 : }
      76             : 
      77           0 : void SmoothTranslator::sharpen()
      78             : {
      79           0 :         init(vect_show);
      80           0 : }
      81             : 
      82       26425 : void SmoothTranslator::update(v3f vect_new, bool is_end_position, float update_interval)
      83             : {
      84       26425 :         aim_is_end = is_end_position;
      85       26425 :         vect_old = vect_show;
      86       26425 :         vect_aim = vect_new;
      87       26425 :         if(update_interval > 0)
      88             :         {
      89       26417 :                 anim_time = update_interval;
      90             :         } else {
      91           8 :                 if(anim_time < 0.001 || anim_time > 1.0)
      92           8 :                         anim_time = anim_time_counter;
      93             :                 else
      94           0 :                         anim_time = anim_time * 0.9 + anim_time_counter * 0.1;
      95             :         }
      96       26425 :         anim_time_counter = 0;
      97       26425 :         anim_counter = 0;
      98       26425 : }
      99             : 
     100       26190 : void SmoothTranslator::translate(f32 dtime)
     101             : {
     102       26190 :         anim_time_counter = anim_time_counter + dtime;
     103       26190 :         anim_counter = anim_counter + dtime;
     104       26190 :         v3f vect_move = vect_aim - vect_old;
     105       26190 :         f32 moveratio = 1.0;
     106       26190 :         if(anim_time > 0.001)
     107       26186 :                 moveratio = anim_time_counter / anim_time;
     108             :         // Move a bit less than should, to avoid oscillation
     109       26190 :         moveratio = moveratio * 0.8;
     110       26190 :         float move_end = 1.5;
     111       26190 :         if(aim_is_end)
     112        8179 :                 move_end = 1.0;
     113       26190 :         if(moveratio > move_end)
     114           2 :                 moveratio = move_end;
     115       26190 :         vect_show = vect_old + vect_move * moveratio;
     116       26190 : }
     117             : 
     118           0 : bool SmoothTranslator::is_moving()
     119             : {
     120           0 :         return ((anim_time_counter / anim_time) < 1.4);
     121             : }
     122             : 
     123             : /*
     124             :         Other stuff
     125             : */
     126             : 
     127           0 : static void setBillboardTextureMatrix(scene::IBillboardSceneNode *bill,
     128             :                 float txs, float tys, int col, int row)
     129             : {
     130           0 :         video::SMaterial& material = bill->getMaterial(0);
     131           0 :         core::matrix4& matrix = material.getTextureMatrix(0);
     132           0 :         matrix.setTextureTranslate(txs*col, tys*row);
     133           0 :         matrix.setTextureScale(txs, tys);
     134           0 : }
     135             : 
     136             : /*
     137             :         TestCAO
     138             : */
     139             : 
     140             : class TestCAO : public ClientActiveObject
     141             : {
     142             : public:
     143             :         TestCAO(IGameDef *gamedef, ClientEnvironment *env);
     144             :         virtual ~TestCAO();
     145             : 
     146           1 :         ActiveObjectType getType() const
     147             :         {
     148           1 :                 return ACTIVEOBJECT_TYPE_TEST;
     149             :         }
     150             : 
     151             :         static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
     152             : 
     153             :         void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
     154             :                         IrrlichtDevice *irr);
     155             :         void removeFromScene(bool permanent);
     156             :         void updateLight(u8 light_at_pos);
     157             :         v3s16 getLightPosition();
     158             :         void updateNodePos();
     159             : 
     160             :         void step(float dtime, ClientEnvironment *env);
     161             : 
     162             :         void processMessage(const std::string &data);
     163             : 
     164           0 :         bool getCollisionBox(aabb3f *toset) { return false; }
     165             : private:
     166             :         scene::IMeshSceneNode *m_node;
     167             :         v3f m_position;
     168             : };
     169             : 
     170             : // Prototype
     171           1 : TestCAO proto_TestCAO(NULL, NULL);
     172             : 
     173           1 : TestCAO::TestCAO(IGameDef *gamedef, ClientEnvironment *env):
     174             :         ClientActiveObject(0, gamedef, env),
     175             :         m_node(NULL),
     176           1 :         m_position(v3f(0,10*BS,0))
     177             : {
     178           1 :         ClientActiveObject::registerType(getType(), create);
     179           1 : }
     180             : 
     181           1 : TestCAO::~TestCAO()
     182             : {
     183           1 : }
     184             : 
     185           0 : ClientActiveObject* TestCAO::create(IGameDef *gamedef, ClientEnvironment *env)
     186             : {
     187           0 :         return new TestCAO(gamedef, env);
     188             : }
     189             : 
     190           0 : void TestCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
     191             :                         IrrlichtDevice *irr)
     192             : {
     193           0 :         if(m_node != NULL)
     194           0 :                 return;
     195             : 
     196             :         //video::IVideoDriver* driver = smgr->getVideoDriver();
     197             : 
     198           0 :         scene::SMesh *mesh = new scene::SMesh();
     199           0 :         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
     200           0 :         video::SColor c(255,255,255,255);
     201             :         video::S3DVertex vertices[4] =
     202             :         {
     203             :                 video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
     204             :                 video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
     205             :                 video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
     206             :                 video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),
     207           0 :         };
     208           0 :         u16 indices[] = {0,1,2,2,3,0};
     209           0 :         buf->append(vertices, 4, indices, 6);
     210             :         // Set material
     211           0 :         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
     212           0 :         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
     213           0 :         buf->getMaterial().setTexture(0, tsrc->getTextureForMesh("rat.png"));
     214           0 :         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
     215           0 :         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
     216           0 :         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
     217             :         // Add to mesh
     218           0 :         mesh->addMeshBuffer(buf);
     219           0 :         buf->drop();
     220           0 :         m_node = smgr->addMeshSceneNode(mesh, NULL);
     221           0 :         mesh->drop();
     222           0 :         updateNodePos();
     223             : }
     224             : 
     225           0 : void TestCAO::removeFromScene(bool permanent)
     226             : {
     227           0 :         if(m_node == NULL)
     228           0 :                 return;
     229             : 
     230           0 :         m_node->remove();
     231           0 :         m_node = NULL;
     232             : }
     233             : 
     234           0 : void TestCAO::updateLight(u8 light_at_pos)
     235             : {
     236           0 : }
     237             : 
     238           0 : v3s16 TestCAO::getLightPosition()
     239             : {
     240           0 :         return floatToInt(m_position, BS);
     241             : }
     242             : 
     243           0 : void TestCAO::updateNodePos()
     244             : {
     245           0 :         if(m_node == NULL)
     246           0 :                 return;
     247             : 
     248           0 :         m_node->setPosition(m_position);
     249             :         //m_node->setRotation(v3f(0, 45, 0));
     250             : }
     251             : 
     252           0 : void TestCAO::step(float dtime, ClientEnvironment *env)
     253             : {
     254           0 :         if(m_node)
     255             :         {
     256           0 :                 v3f rot = m_node->getRotation();
     257             :                 //infostream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
     258           0 :                 rot.Y += dtime * 180;
     259           0 :                 m_node->setRotation(rot);
     260             :         }
     261           0 : }
     262             : 
     263           0 : void TestCAO::processMessage(const std::string &data)
     264             : {
     265           0 :         infostream<<"TestCAO: Got data: "<<data<<std::endl;
     266           0 :         std::istringstream is(data, std::ios::binary);
     267             :         u16 cmd;
     268           0 :         is>>cmd;
     269           0 :         if(cmd == 0)
     270             :         {
     271           0 :                 v3f newpos;
     272           0 :                 is>>newpos.X;
     273           0 :                 is>>newpos.Y;
     274           0 :                 is>>newpos.Z;
     275           0 :                 m_position = newpos;
     276           0 :                 updateNodePos();
     277             :         }
     278           0 : }
     279             : 
     280             : /*
     281             :         ItemCAO
     282             : */
     283             : 
     284             : class ItemCAO : public ClientActiveObject
     285             : {
     286             : public:
     287             :         ItemCAO(IGameDef *gamedef, ClientEnvironment *env);
     288             :         virtual ~ItemCAO();
     289             : 
     290           1 :         ActiveObjectType getType() const
     291             :         {
     292           1 :                 return ACTIVEOBJECT_TYPE_ITEM;
     293             :         }
     294             : 
     295             :         static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env);
     296             : 
     297             :         void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
     298             :                         IrrlichtDevice *irr);
     299             :         void removeFromScene(bool permanent);
     300             :         void updateLight(u8 light_at_pos);
     301             :         v3s16 getLightPosition();
     302             :         void updateNodePos();
     303             :         void updateInfoText();
     304             :         void updateTexture();
     305             : 
     306             :         void step(float dtime, ClientEnvironment *env);
     307             : 
     308             :         void processMessage(const std::string &data);
     309             : 
     310             :         void initialize(const std::string &data);
     311             : 
     312           0 :         core::aabbox3d<f32>* getSelectionBox()
     313           0 :                 {return &m_selection_box;}
     314           0 :         v3f getPosition()
     315           0 :                 {return m_position;}
     316             : 
     317           0 :         std::string infoText()
     318           0 :                 {return m_infotext;}
     319             : 
     320           0 :         bool getCollisionBox(aabb3f *toset) { return false; }
     321             : private:
     322             :         core::aabbox3d<f32> m_selection_box;
     323             :         scene::IMeshSceneNode *m_node;
     324             :         v3f m_position;
     325             :         std::string m_itemstring;
     326             :         std::string m_infotext;
     327             : };
     328             : 
     329             : #include "inventory.h"
     330             : 
     331             : // Prototype
     332           1 : ItemCAO proto_ItemCAO(NULL, NULL);
     333             : 
     334           1 : ItemCAO::ItemCAO(IGameDef *gamedef, ClientEnvironment *env):
     335             :         ClientActiveObject(0, gamedef, env),
     336             :         m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.),
     337             :         m_node(NULL),
     338           1 :         m_position(v3f(0,10*BS,0))
     339             : {
     340           1 :         if(!gamedef && !env)
     341             :         {
     342           1 :                 ClientActiveObject::registerType(getType(), create);
     343             :         }
     344           1 : }
     345             : 
     346           1 : ItemCAO::~ItemCAO()
     347             : {
     348           1 : }
     349             : 
     350           0 : ClientActiveObject* ItemCAO::create(IGameDef *gamedef, ClientEnvironment *env)
     351             : {
     352           0 :         return new ItemCAO(gamedef, env);
     353             : }
     354             : 
     355           0 : void ItemCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
     356             :                         IrrlichtDevice *irr)
     357             : {
     358           0 :         if(m_node != NULL)
     359           0 :                 return;
     360             : 
     361             :         //video::IVideoDriver* driver = smgr->getVideoDriver();
     362             : 
     363           0 :         scene::SMesh *mesh = new scene::SMesh();
     364           0 :         scene::IMeshBuffer *buf = new scene::SMeshBuffer();
     365           0 :         video::SColor c(255,255,255,255);
     366             :         video::S3DVertex vertices[4] =
     367             :         {
     368             :                 /*video::S3DVertex(-BS/2,-BS/4,0, 0,0,0, c, 0,1),
     369             :                 video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1),
     370             :                 video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0),
     371             :                 video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),*/
     372             :                 video::S3DVertex(BS/3.,0,0, 0,0,0, c, 0,1),
     373             :                 video::S3DVertex(-BS/3.,0,0, 0,0,0, c, 1,1),
     374             :                 video::S3DVertex(-BS/3.,0+BS*2./3.,0, 0,0,0, c, 1,0),
     375             :                 video::S3DVertex(BS/3.,0+BS*2./3.,0, 0,0,0, c, 0,0),
     376           0 :         };
     377           0 :         u16 indices[] = {0,1,2,2,3,0};
     378           0 :         buf->append(vertices, 4, indices, 6);
     379             :         // Set material
     380           0 :         buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
     381           0 :         buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
     382             :         // Initialize with a generated placeholder texture
     383           0 :         buf->getMaterial().setTexture(0, tsrc->getTexture(""));
     384           0 :         buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
     385           0 :         buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
     386           0 :         buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
     387             :         // Add to mesh
     388           0 :         mesh->addMeshBuffer(buf);
     389           0 :         buf->drop();
     390           0 :         m_node = smgr->addMeshSceneNode(mesh, NULL);
     391           0 :         mesh->drop();
     392           0 :         updateNodePos();
     393             : 
     394             :         /*
     395             :                 Update image of node
     396             :         */
     397             : 
     398           0 :         updateTexture();
     399             : }
     400             : 
     401           0 : void ItemCAO::removeFromScene(bool permanent)
     402             : {
     403           0 :         if(m_node == NULL)
     404           0 :                 return;
     405             : 
     406           0 :         m_node->remove();
     407           0 :         m_node = NULL;
     408             : }
     409             : 
     410           0 : void ItemCAO::updateLight(u8 light_at_pos)
     411             : {
     412           0 :         if(m_node == NULL)
     413           0 :                 return;
     414             : 
     415           0 :         u8 li = decode_light(light_at_pos);
     416           0 :         video::SColor color(255,li,li,li);
     417           0 :         setMeshColor(m_node->getMesh(), color);
     418             : }
     419             : 
     420           0 : v3s16 ItemCAO::getLightPosition()
     421             : {
     422           0 :         return floatToInt(m_position + v3f(0,0.5*BS,0), BS);
     423             : }
     424             : 
     425           0 : void ItemCAO::updateNodePos()
     426             : {
     427           0 :         if(m_node == NULL)
     428           0 :                 return;
     429             : 
     430           0 :         m_node->setPosition(m_position);
     431             : }
     432             : 
     433           0 : void ItemCAO::updateInfoText()
     434             : {
     435             :         try{
     436           0 :                 IItemDefManager *idef = m_gamedef->idef();
     437           0 :                 ItemStack item;
     438           0 :                 item.deSerialize(m_itemstring, idef);
     439           0 :                 if(item.isKnown(idef))
     440           0 :                         m_infotext = item.getDefinition(idef).description;
     441             :                 else
     442           0 :                         m_infotext = "Unknown item: '" + m_itemstring + "'";
     443           0 :                 if(item.count >= 2)
     444           0 :                         m_infotext += " (" + itos(item.count) + ")";
     445             :         }
     446           0 :         catch(SerializationError &e)
     447             :         {
     448           0 :                 m_infotext = "Unknown item: '" + m_itemstring + "'";
     449             :         }
     450           0 : }
     451             : 
     452           0 : void ItemCAO::updateTexture()
     453             : {
     454           0 :         if(m_node == NULL)
     455           0 :                 return;
     456             : 
     457             :         // Create an inventory item to see what is its image
     458           0 :         std::istringstream is(m_itemstring, std::ios_base::binary);
     459           0 :         video::ITexture *texture = NULL;
     460             :         try{
     461           0 :                 IItemDefManager *idef = m_gamedef->idef();
     462           0 :                 ItemStack item;
     463           0 :                 item.deSerialize(is, idef);
     464           0 :                 texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_gamedef);
     465             :         }
     466           0 :         catch(SerializationError &e)
     467             :         {
     468           0 :                 infostream<<"WARNING: "<<__FUNCTION_NAME
     469           0 :                                 <<": error deSerializing itemstring \""
     470           0 :                                 <<m_itemstring<<std::endl;
     471             :         }
     472             : 
     473             :         // Set meshbuffer texture
     474           0 :         m_node->getMaterial(0).setTexture(0, texture);
     475             : }
     476             : 
     477             : 
     478           0 : void ItemCAO::step(float dtime, ClientEnvironment *env)
     479             : {
     480           0 :         if(m_node)
     481             :         {
     482             :                 /*v3f rot = m_node->getRotation();
     483             :                 rot.Y += dtime * 120;
     484             :                 m_node->setRotation(rot);*/
     485           0 :                 LocalPlayer *player = env->getLocalPlayer();
     486             :                 assert(player);
     487           0 :                 v3f rot = m_node->getRotation();
     488           0 :                 rot.Y = 180.0 - (player->getYaw());
     489           0 :                 m_node->setRotation(rot);
     490             :         }
     491           0 : }
     492             : 
     493           0 : void ItemCAO::processMessage(const std::string &data)
     494             : {
     495             :         //infostream<<"ItemCAO: Got message"<<std::endl;
     496           0 :         std::istringstream is(data, std::ios::binary);
     497             :         // command
     498           0 :         u8 cmd = readU8(is);
     499           0 :         if(cmd == 0)
     500             :         {
     501             :                 // pos
     502           0 :                 m_position = readV3F1000(is);
     503           0 :                 updateNodePos();
     504             :         }
     505           0 :         if(cmd == 1)
     506             :         {
     507             :                 // itemstring
     508           0 :                 m_itemstring = deSerializeString(is);
     509           0 :                 updateInfoText();
     510           0 :                 updateTexture();
     511             :         }
     512           0 : }
     513             : 
     514           0 : void ItemCAO::initialize(const std::string &data)
     515             : {
     516           0 :         infostream<<"ItemCAO: Got init data"<<std::endl;
     517             : 
     518             :         {
     519           0 :                 std::istringstream is(data, std::ios::binary);
     520             :                 // version
     521           0 :                 u8 version = readU8(is);
     522             :                 // check version
     523           0 :                 if(version != 0)
     524           0 :                         return;
     525             :                 // pos
     526           0 :                 m_position = readV3F1000(is);
     527             :                 // itemstring
     528           0 :                 m_itemstring = deSerializeString(is);
     529             :         }
     530             : 
     531           0 :         updateNodePos();
     532           0 :         updateInfoText();
     533             : }
     534             : 
     535             : /*
     536             :         GenericCAO
     537             : */
     538             : 
     539             : #include "genericobject.h"
     540             : 
     541          45 : GenericCAO::GenericCAO(IGameDef *gamedef, ClientEnvironment *env):
     542             :                 ClientActiveObject(0, gamedef, env),
     543             :                 //
     544             :                 m_is_player(false),
     545             :                 m_is_local_player(false),
     546             :                 //
     547             :                 m_smgr(NULL),
     548             :                 m_irr(NULL),
     549             :                 m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.),
     550             :                 m_meshnode(NULL),
     551             :                 m_animated_meshnode(NULL),
     552             :                 m_wield_meshnode(NULL),
     553             :                 m_spritenode(NULL),
     554             :                 m_nametag_color(video::SColor(255, 255, 255, 255)),
     555             :                 m_textnode(NULL),
     556             :                 m_position(v3f(0,10*BS,0)),
     557             :                 m_velocity(v3f(0,0,0)),
     558             :                 m_acceleration(v3f(0,0,0)),
     559             :                 m_yaw(0),
     560             :                 m_hp(1),
     561             :                 m_tx_size(1,1),
     562             :                 m_tx_basepos(0,0),
     563             :                 m_initial_tx_basepos_set(false),
     564             :                 m_tx_select_horiz_by_yawpitch(false),
     565             :                 m_animation_range(v2s32(0,0)),
     566             :                 m_animation_speed(15),
     567             :                 m_animation_blend(0),
     568             :                 m_animation_loop(true),
     569             :                 m_bone_position(std::map<std::string, core::vector2d<v3f> >()),
     570             :                 m_attachment_bone(""),
     571             :                 m_attachment_position(v3f(0,0,0)),
     572             :                 m_attachment_rotation(v3f(0,0,0)),
     573             :                 m_attached_to_local(false),
     574             :                 m_anim_frame(0),
     575             :                 m_anim_num_frames(1),
     576             :                 m_anim_framelength(0.2),
     577             :                 m_anim_timer(0),
     578             :                 m_reset_textures_timer(-1),
     579             :                 m_visuals_expired(false),
     580             :                 m_step_distance_counter(0),
     581             :                 m_last_light(255),
     582          45 :                 m_is_visible(false)
     583             : {
     584          45 :         if(gamedef == NULL)
     585           1 :                 ClientActiveObject::registerType(getType(), create);
     586          45 : }
     587             : 
     588        2889 : bool GenericCAO::getCollisionBox(aabb3f *toset)
     589             : {
     590        2889 :         if (m_prop.physical)
     591             :         {
     592             :                 //update collision box
     593         200 :                 toset->MinEdge = m_prop.collisionbox.MinEdge * BS;
     594         200 :                 toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS;
     595             : 
     596         200 :                 toset->MinEdge += m_position;
     597         200 :                 toset->MaxEdge += m_position;
     598             : 
     599         200 :                 return true;
     600             :         }
     601             : 
     602        2689 :         return false;
     603             : }
     604             : 
     605         200 : bool GenericCAO::collideWithObjects()
     606             : {
     607         200 :         return m_prop.collideWithObjects;
     608             : }
     609             : 
     610          44 : void GenericCAO::initialize(const std::string &data)
     611             : {
     612          44 :         infostream<<"GenericCAO: Got init data"<<std::endl;
     613          88 :         std::istringstream is(data, std::ios::binary);
     614          44 :         int num_messages = 0;
     615             :         // version
     616          44 :         u8 version = readU8(is);
     617             :         // check version
     618          44 :         if(version == 1) // In PROTOCOL_VERSION 14
     619             :         {
     620          44 :                 m_name = deSerializeString(is);
     621          44 :                 m_is_player = readU8(is);
     622          44 :                 m_id = readS16(is);
     623          44 :                 m_position = readV3F1000(is);
     624          44 :                 m_yaw = readF1000(is);
     625          44 :                 m_hp = readS16(is);
     626          44 :                 num_messages = readU8(is);
     627             :         }
     628           0 :         else if(version == 0) // In PROTOCOL_VERSION 13
     629             :         {
     630           0 :                 m_name = deSerializeString(is);
     631           0 :                 m_is_player = readU8(is);
     632           0 :                 m_position = readV3F1000(is);
     633           0 :                 m_yaw = readF1000(is);
     634           0 :                 m_hp = readS16(is);
     635           0 :                 num_messages = readU8(is);
     636             :         }
     637             :         else
     638             :         {
     639           0 :                 errorstream<<"GenericCAO: Unsupported init data version"
     640           0 :                                 <<std::endl;
     641           0 :                 return;
     642             :         }
     643             : 
     644         221 :         for(int i=0; i<num_messages; i++)
     645             :         {
     646         354 :                 std::string message = deSerializeLongString(is);
     647         177 :                 processMessage(message);
     648             :         }
     649             : 
     650          44 :         pos_translator.init(m_position);
     651          44 :         updateNodePos();
     652             : 
     653          44 :         if(m_is_player)
     654             :         {
     655           1 :                 Player *player = m_env->getPlayer(m_name.c_str());
     656           1 :                 if(player && player->isLocal())
     657             :                 {
     658           1 :                         m_is_local_player = true;
     659           1 :                         m_is_visible = false;
     660           1 :                         LocalPlayer* localplayer = dynamic_cast<LocalPlayer*>(player);
     661             : 
     662             :                         assert( localplayer != NULL );
     663           1 :                         localplayer->setCAO(this);
     664             :                 }
     665           1 :                 m_env->addPlayerName(m_name.c_str());
     666             :         }
     667             : }
     668             : 
     669         134 : GenericCAO::~GenericCAO()
     670             : {
     671          45 :         if(m_is_player)
     672             :         {
     673           1 :                 m_env->removePlayerName(m_name.c_str());
     674             :         }
     675          45 :         removeFromScene(true);
     676          89 : }
     677             : 
     678        1345 : core::aabbox3d<f32>* GenericCAO::getSelectionBox()
     679             : {
     680        1345 :         if(!m_prop.is_visible || !m_is_visible || m_is_local_player || getParent() != NULL)
     681        1153 :                 return NULL;
     682         192 :         return &m_selection_box;
     683             : }
     684             : 
     685      293372 : v3f GenericCAO::getPosition()
     686             : {
     687      293372 :         if (getParent() != NULL) {
     688           0 :                 scene::ISceneNode *node = getSceneNode();
     689           0 :                 if (node)
     690           0 :                         return node->getAbsolutePosition();
     691             :                 else
     692           0 :                         return m_position;
     693             :         }
     694      293372 :         return pos_translator.vect_show;
     695             : }
     696             : 
     697       55221 : scene::ISceneNode* GenericCAO::getSceneNode()
     698             : {
     699       55221 :         if (m_meshnode)
     700       32421 :                 return m_meshnode;
     701       22800 :         if (m_animated_meshnode)
     702       18815 :                 return m_animated_meshnode;
     703        3985 :         if (m_wield_meshnode)
     704        3779 :                 return m_wield_meshnode;
     705         206 :         if (m_spritenode)
     706           0 :                 return m_spritenode;
     707         206 :         return NULL;
     708             : }
     709             : 
     710           0 : scene::IMeshSceneNode* GenericCAO::getMeshSceneNode()
     711             : {
     712           0 :         return m_meshnode;
     713             : }
     714             : 
     715           0 : scene::IAnimatedMeshSceneNode* GenericCAO::getAnimatedMeshSceneNode()
     716             : {
     717           0 :         return m_animated_meshnode;
     718             : }
     719             : 
     720           0 : WieldMeshSceneNode* GenericCAO::getWieldMeshSceneNode()
     721             : {
     722           0 :         return m_wield_meshnode;
     723             : }
     724             : 
     725           0 : scene::IBillboardSceneNode* GenericCAO::getSpriteSceneNode()
     726             : {
     727           0 :         return m_spritenode;
     728             : }
     729             : 
     730           0 : void GenericCAO::setChildrenVisible(bool toset)
     731             : {
     732           0 :         for (std::vector<u16>::size_type i = 0; i < m_children.size(); i++) {
     733           0 :                 GenericCAO *obj = m_env->getGenericCAO(m_children[i]);
     734           0 :                 if (obj) {
     735           0 :                         obj->setVisible(toset);
     736             :                 }
     737             :         }
     738           0 : }
     739             : 
     740           0 : void GenericCAO::setAttachments()
     741             : {
     742           0 :         updateAttachments();
     743           0 : }
     744             : 
     745      402170 : ClientActiveObject* GenericCAO::getParent()
     746             : {
     747      402170 :         ClientActiveObject *obj = NULL;
     748             : 
     749      402170 :         u16 attached_id = m_env->attachement_parent_ids[getId()];
     750             : 
     751      402170 :         if ((attached_id != 0) &&
     752           0 :                         (attached_id != getId())) {
     753           0 :                 obj = m_env->getActiveObject(attached_id);
     754             :         }
     755      402170 :         return obj;
     756             : }
     757             : 
     758         138 : void GenericCAO::removeFromScene(bool permanent)
     759             : {
     760             :         // Should be true when removing the object permanently and false when refreshing (eg: updating visuals)
     761         138 :         if((m_env != NULL) && (permanent))
     762             :         {
     763          63 :                 for (std::vector<u16>::size_type i = 0; i < m_children.size(); i++) {
     764           0 :                         u16 ci = m_children[i];
     765           0 :                         if (m_env->attachement_parent_ids[ci] == getId()) {
     766           0 :                                 m_env->attachement_parent_ids[ci] = 0;
     767             :                         }
     768             :                 }
     769             : 
     770          63 :                 m_env->attachement_parent_ids[getId()] = 0;
     771             : 
     772          63 :                 LocalPlayer* player = m_env->getLocalPlayer();
     773          63 :                 if (this == player->parent) {
     774           0 :                         player->parent = NULL;
     775           0 :                         player->isAttached = false;
     776             :                 }
     777             :         }
     778             : 
     779         138 :         if(m_meshnode)
     780             :         {
     781          67 :                 m_meshnode->remove();
     782          67 :                 m_meshnode->drop();
     783          67 :                 m_meshnode = NULL;
     784             :         }
     785         138 :         if(m_animated_meshnode)
     786             :         {
     787          26 :                 m_animated_meshnode->remove();
     788          26 :                 m_animated_meshnode->drop();
     789          26 :                 m_animated_meshnode = NULL;
     790             :         }
     791         138 :         if(m_wield_meshnode)
     792             :         {
     793          25 :                 m_wield_meshnode->remove();
     794          25 :                 m_wield_meshnode->drop();
     795          25 :                 m_wield_meshnode = NULL;
     796             :         }
     797         138 :         if(m_spritenode)
     798             :         {
     799           0 :                 m_spritenode->remove();
     800           0 :                 m_spritenode->drop();
     801           0 :                 m_spritenode = NULL;
     802             :         }
     803         138 :         if (m_textnode)
     804             :         {
     805           0 :                 m_textnode->remove();
     806           0 :                 m_textnode->drop();
     807           0 :                 m_textnode = NULL;
     808             :         }
     809         138 : }
     810             : 
     811         118 : void GenericCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc,
     812             :                 IrrlichtDevice *irr)
     813             : {
     814         118 :         m_smgr = smgr;
     815         118 :         m_irr = irr;
     816             : 
     817         118 :         if (getSceneNode() != NULL)
     818           0 :                 return;
     819             : 
     820         118 :         m_visuals_expired = false;
     821             : 
     822         118 :         if(!m_prop.is_visible)
     823           0 :                 return;
     824             : 
     825             :         //video::IVideoDriver* driver = smgr->getVideoDriver();
     826             : 
     827         118 :         if(m_prop.visual == "sprite")
     828             :         {
     829           0 :                 infostream<<"GenericCAO::addToScene(): single_sprite"<<std::endl;
     830           0 :                 m_spritenode = smgr->addBillboardSceneNode(
     831           0 :                                 NULL, v2f(1, 1), v3f(0,0,0), -1);
     832           0 :                 m_spritenode->grab();
     833           0 :                 m_spritenode->setMaterialTexture(0,
     834           0 :                                 tsrc->getTextureForMesh("unknown_node.png"));
     835           0 :                 m_spritenode->setMaterialFlag(video::EMF_LIGHTING, false);
     836           0 :                 m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
     837           0 :                 m_spritenode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
     838           0 :                 m_spritenode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
     839           0 :                 u8 li = m_last_light;
     840           0 :                 m_spritenode->setColor(video::SColor(255,li,li,li));
     841           0 :                 m_spritenode->setSize(m_prop.visual_size*BS);
     842             :                 {
     843           0 :                         const float txs = 1.0 / 1;
     844           0 :                         const float tys = 1.0 / 1;
     845           0 :                         setBillboardTextureMatrix(m_spritenode,
     846           0 :                                         txs, tys, 0, 0);
     847             :                 }
     848             :         }
     849         118 :         else if(m_prop.visual == "upright_sprite") {
     850          67 :                 scene::SMesh *mesh = new scene::SMesh();
     851          67 :                 double dx = BS*m_prop.visual_size.X/2;
     852          67 :                 double dy = BS*m_prop.visual_size.Y/2;
     853             :                 { // Front
     854          67 :                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
     855          67 :                 u8 li = m_last_light;
     856          67 :                 video::SColor c(255,li,li,li);
     857             :                 video::S3DVertex vertices[4] =
     858             :                 {
     859             :                         video::S3DVertex(-dx,-dy,0, 0,0,0, c, 0,1),
     860             :                         video::S3DVertex(dx,-dy,0, 0,0,0, c, 1,1),
     861             :                         video::S3DVertex(dx,dy,0, 0,0,0, c, 1,0),
     862             :                         video::S3DVertex(-dx,dy,0, 0,0,0, c, 0,0),
     863          67 :                 };
     864          67 :                 u16 indices[] = {0,1,2,2,3,0};
     865          67 :                 buf->append(vertices, 4, indices, 6);
     866             :                 // Set material
     867          67 :                 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
     868          67 :                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
     869          67 :                 buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
     870          67 :                 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
     871             :                 // Add to mesh
     872          67 :                 mesh->addMeshBuffer(buf);
     873          67 :                 buf->drop();
     874             :                 }
     875             :                 { // Back
     876          67 :                 scene::IMeshBuffer *buf = new scene::SMeshBuffer();
     877          67 :                 u8 li = m_last_light;
     878          67 :                 video::SColor c(255,li,li,li);
     879             :                 video::S3DVertex vertices[4] =
     880             :                 {
     881             :                         video::S3DVertex(dx,-dy,0, 0,0,0, c, 1,1),
     882             :                         video::S3DVertex(-dx,-dy,0, 0,0,0, c, 0,1),
     883             :                         video::S3DVertex(-dx,dy,0, 0,0,0, c, 0,0),
     884             :                         video::S3DVertex(dx,dy,0, 0,0,0, c, 1,0),
     885          67 :                 };
     886          67 :                 u16 indices[] = {0,1,2,2,3,0};
     887          67 :                 buf->append(vertices, 4, indices, 6);
     888             :                 // Set material
     889          67 :                 buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
     890          67 :                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
     891          67 :                 buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
     892          67 :                 buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
     893             :                 // Add to mesh
     894          67 :                 mesh->addMeshBuffer(buf);
     895          67 :                 buf->drop();
     896             :                 }
     897          67 :                 m_meshnode = smgr->addMeshSceneNode(mesh, NULL);
     898          67 :                 m_meshnode->grab();
     899          67 :                 mesh->drop();
     900             :                 // Set it to use the materials of the meshbuffers directly.
     901             :                 // This is needed for changing the texture in the future
     902          67 :                 m_meshnode->setReadOnlyMaterials(true);
     903             :         }
     904          51 :         else if(m_prop.visual == "cube") {
     905           0 :                 infostream<<"GenericCAO::addToScene(): cube"<<std::endl;
     906           0 :                 scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));
     907           0 :                 m_meshnode = smgr->addMeshSceneNode(mesh, NULL);
     908           0 :                 m_meshnode->grab();
     909           0 :                 mesh->drop();
     910             : 
     911           0 :                 m_meshnode->setScale(v3f(m_prop.visual_size.X,
     912             :                                 m_prop.visual_size.Y,
     913           0 :                                 m_prop.visual_size.X));
     914           0 :                 u8 li = m_last_light;
     915           0 :                 setMeshColor(m_meshnode->getMesh(), video::SColor(255,li,li,li));
     916             : 
     917           0 :                 m_meshnode->setMaterialFlag(video::EMF_LIGHTING, false);
     918           0 :                 m_meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
     919           0 :                 m_meshnode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
     920           0 :                 m_meshnode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
     921             :         }
     922          51 :         else if(m_prop.visual == "mesh") {
     923          26 :                 infostream<<"GenericCAO::addToScene(): mesh"<<std::endl;
     924          26 :                 scene::IAnimatedMesh *mesh = m_gamedef->getMesh(m_prop.mesh);
     925          26 :                 if(mesh)
     926             :                 {
     927          26 :                         m_animated_meshnode = smgr->addAnimatedMeshSceneNode(mesh, NULL);
     928          26 :                         m_animated_meshnode->grab();
     929          26 :                         mesh->drop(); // The scene node took hold of it
     930          26 :                         m_animated_meshnode->animateJoints(); // Needed for some animations
     931         104 :                         m_animated_meshnode->setScale(v3f(m_prop.visual_size.X,
     932             :                                         m_prop.visual_size.Y,
     933          78 :                                         m_prop.visual_size.X));
     934          26 :                         u8 li = m_last_light;
     935          26 :                         setMeshColor(m_animated_meshnode->getMesh(), video::SColor(255,li,li,li));
     936             : 
     937          26 :                         m_animated_meshnode->setMaterialFlag(video::EMF_LIGHTING, false);
     938          26 :                         m_animated_meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
     939          26 :                         m_animated_meshnode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
     940          26 :                         m_animated_meshnode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
     941             :                 }
     942             :                 else
     943           0 :                         errorstream<<"GenericCAO::addToScene(): Could not load mesh "<<m_prop.mesh<<std::endl;
     944             :         }
     945          25 :         else if(m_prop.visual == "wielditem") {
     946          25 :                 infostream<<"GenericCAO::addToScene(): wielditem"<<std::endl;
     947          25 :                 infostream<<"textures: "<<m_prop.textures.size()<<std::endl;
     948          25 :                 if(m_prop.textures.size() >= 1){
     949          25 :                         infostream<<"textures[0]: "<<m_prop.textures[0]<<std::endl;
     950          25 :                         IItemDefManager *idef = m_gamedef->idef();
     951          50 :                         ItemStack item(m_prop.textures[0], 1, 0, "", idef);
     952             : 
     953             :                         m_wield_meshnode = new WieldMeshSceneNode(
     954          25 :                                         smgr->getRootSceneNode(), smgr, -1);
     955          25 :                         m_wield_meshnode->setItem(item, m_gamedef);
     956             : 
     957         125 :                         m_wield_meshnode->setScale(v3f(m_prop.visual_size.X/2,
     958          25 :                                         m_prop.visual_size.Y/2,
     959          75 :                                         m_prop.visual_size.X/2));
     960          25 :                         u8 li = m_last_light;
     961          25 :                         m_wield_meshnode->setColor(video::SColor(255,li,li,li));
     962             :                 }
     963             :         } else {
     964           0 :                 infostream<<"GenericCAO::addToScene(): \""<<m_prop.visual
     965           0 :                                 <<"\" not supported"<<std::endl;
     966             :         }
     967         118 :         updateTextures("");
     968             : 
     969         118 :         scene::ISceneNode *node = getSceneNode();
     970         118 :         if (node && m_is_player && !m_is_local_player) {
     971             :                 // Add a text node for showing the name
     972           0 :                 gui::IGUIEnvironment* gui = irr->getGUIEnvironment();
     973           0 :                 std::wstring wname = narrow_to_wide(m_name);
     974           0 :                 m_textnode = smgr->addTextSceneNode(gui->getSkin()->getFont(),
     975           0 :                                 wname.c_str(), m_nametag_color, node);
     976           0 :                 m_textnode->grab();
     977           0 :                 m_textnode->setPosition(v3f(0, BS*1.1, 0));
     978             :         }
     979             : 
     980         118 :         updateNodePos();
     981         118 :         updateAnimation();
     982         118 :         updateBonePosition();
     983         118 :         updateAttachments();
     984             : }
     985             : 
     986        3554 : void GenericCAO::updateLight(u8 light_at_pos)
     987             : {
     988        3554 :         u8 li = decode_light(light_at_pos);
     989        3554 :         if(li != m_last_light)
     990             :         {
     991          91 :                 m_last_light = li;
     992          91 :                 video::SColor color(255,li,li,li);
     993          91 :                 if(m_meshnode)
     994          10 :                         setMeshColor(m_meshnode->getMesh(), color);
     995          91 :                 if(m_animated_meshnode)
     996          66 :                         setMeshColor(m_animated_meshnode->getMesh(), color);
     997          91 :                 if(m_wield_meshnode)
     998          15 :                         m_wield_meshnode->setColor(color);
     999          91 :                 if(m_spritenode)
    1000           0 :                         m_spritenode->setColor(color);
    1001             :         }
    1002        3554 : }
    1003             : 
    1004        3554 : v3s16 GenericCAO::getLightPosition()
    1005             : {
    1006        3554 :         return floatToInt(m_position, BS);
    1007             : }
    1008             : 
    1009       28598 : void GenericCAO::updateNodePos()
    1010             : {
    1011       28598 :         if (getParent() != NULL)
    1012           0 :                 return;
    1013             : 
    1014       28598 :         scene::ISceneNode *node = getSceneNode();
    1015             : 
    1016       28598 :         if (node) {
    1017       28554 :                 v3s16 camera_offset = m_env->getCameraOffset();
    1018       28554 :                 node->setPosition(pos_translator.vect_show - intToFloat(camera_offset, BS));
    1019       28554 :                 if (node != m_spritenode) { // rotate if not a sprite
    1020       28554 :                         v3f rot = node->getRotation();
    1021       28554 :                         rot.Y = -m_yaw;
    1022       28554 :                         node->setRotation(rot);
    1023             :                 }
    1024             :         }
    1025             : }
    1026             : 
    1027       26190 : void GenericCAO::step(float dtime, ClientEnvironment *env)
    1028             : {
    1029             :         // Handel model of local player instantly to prevent lags
    1030       26190 :         if(m_is_local_player)
    1031             :         {
    1032        1166 :                 LocalPlayer *player = m_env->getLocalPlayer();
    1033             : 
    1034        1166 :                 if (m_is_visible)
    1035             :                 {
    1036           0 :                         int old_anim = player->last_animation;
    1037           0 :                         float old_anim_speed = player->last_animation_speed;
    1038           0 :                         m_position = player->getPosition() + v3f(0,BS,0);
    1039           0 :                         m_velocity = v3f(0,0,0);
    1040           0 :                         m_acceleration = v3f(0,0,0);
    1041           0 :                         pos_translator.vect_show = m_position;
    1042           0 :                         m_yaw = player->getYaw();
    1043           0 :                         PlayerControl controls = player->getPlayerControl();
    1044             : 
    1045           0 :                         bool walking = false;
    1046           0 :                         if(controls.up || controls.down || controls.left || controls.right)
    1047           0 :                                 walking = true;
    1048             : 
    1049           0 :                         f32 new_speed = player->local_animation_speed;
    1050           0 :                         v2s32 new_anim = v2s32(0,0);
    1051           0 :                         bool allow_update = false;
    1052             : 
    1053             :                         // increase speed if using fast or flying fast
    1054           0 :                         if((g_settings->getBool("fast_move") &&
    1055           0 :                                         m_gamedef->checkLocalPrivilege("fast")) &&
    1056           0 :                                         (controls.aux1 ||
    1057           0 :                                         (!player->touching_ground &&
    1058           0 :                                         g_settings->getBool("free_move") &&
    1059           0 :                                         m_gamedef->checkLocalPrivilege("fly"))))
    1060           0 :                                         new_speed *= 1.5;
    1061             :                         // slowdown speed if sneeking
    1062           0 :                         if(controls.sneak && walking)
    1063           0 :                                 new_speed /= 2;
    1064             : 
    1065           0 :                         if(walking && (controls.LMB || controls.RMB))
    1066             :                         {
    1067           0 :                                 new_anim = player->local_animations[3];
    1068           0 :                                 player->last_animation = WD_ANIM;
    1069           0 :                         } else if(walking) {
    1070           0 :                                 new_anim = player->local_animations[1];
    1071           0 :                                 player->last_animation = WALK_ANIM;
    1072           0 :                         } else if(controls.LMB || controls.RMB) {
    1073           0 :                                 new_anim = player->local_animations[2];
    1074           0 :                                 player->last_animation = DIG_ANIM;
    1075             :                         }
    1076             : 
    1077             :                         // Apply animations if input detected and not attached
    1078             :                         // or set idle animation
    1079           0 :                         if ((new_anim.X + new_anim.Y) > 0 && !player->isAttached)
    1080             :                         {
    1081           0 :                                 allow_update = true;
    1082           0 :                                 m_animation_range = new_anim;
    1083           0 :                                 m_animation_speed = new_speed;
    1084           0 :                                 player->last_animation_speed = m_animation_speed;
    1085             :                         } else {
    1086           0 :                                 player->last_animation = NO_ANIM;
    1087             : 
    1088           0 :                                 if (old_anim != NO_ANIM)
    1089             :                                 {
    1090           0 :                                         m_animation_range = player->local_animations[0];
    1091           0 :                                         updateAnimation();
    1092             :                                 }
    1093             :                         }
    1094             : 
    1095             :                         // Update local player animations
    1096           0 :                         if ((player->last_animation != old_anim ||
    1097           0 :                                 m_animation_speed != old_anim_speed) &&
    1098           0 :                                 player->last_animation != NO_ANIM && allow_update)
    1099           0 :                                         updateAnimation();
    1100             : 
    1101             :                 }
    1102             :         }
    1103             : 
    1104       26190 :         if(m_visuals_expired && m_smgr && m_irr){
    1105          74 :                 m_visuals_expired = false;
    1106             : 
    1107             :                 // Attachments, part 1: All attached objects must be unparented first,
    1108             :                 // or Irrlicht causes a segmentation fault
    1109         222 :                 for(std::vector<u16>::iterator ci = m_children.begin();
    1110         148 :                                 ci != m_children.end();)
    1111             :                 {
    1112           0 :                         if (m_env->attachement_parent_ids[*ci] != getId()) {
    1113           0 :                                 ci = m_children.erase(ci);
    1114           0 :                                 continue;
    1115             :                         }
    1116           0 :                         ClientActiveObject *obj = m_env->getActiveObject(*ci);
    1117           0 :                         if (obj) {
    1118           0 :                                 scene::ISceneNode *child_node = obj->getSceneNode();
    1119           0 :                                 if (child_node)
    1120           0 :                                         child_node->setParent(m_smgr->getRootSceneNode());
    1121             :                         }
    1122           0 :                         ++ci;
    1123             :                 }
    1124             : 
    1125          74 :                 removeFromScene(false);
    1126          74 :                 addToScene(m_smgr, m_gamedef->tsrc(), m_irr);
    1127             : 
    1128             :                 // Attachments, part 2: Now that the parent has been refreshed, put its attachments back
    1129          74 :                 for (std::vector<u16>::size_type i = 0; i < m_children.size(); i++) {
    1130             :                         // Get the object of the child
    1131           0 :                         ClientActiveObject *obj = m_env->getActiveObject(m_children[i]);
    1132           0 :                         if (obj)
    1133           0 :                                 obj->setAttachments();
    1134             :                 }
    1135             :         }
    1136             : 
    1137             :         // Make sure m_is_visible is always applied
    1138       26190 :         scene::ISceneNode *node = getSceneNode();
    1139       26190 :         if (node)
    1140       26190 :                 node->setVisible(m_is_visible);
    1141             : 
    1142       26190 :         if(getParent() != NULL) // Attachments should be glued to their parent by Irrlicht
    1143             :         {
    1144             :                 // Set these for later
    1145           0 :                 m_position = getPosition();
    1146           0 :                 m_velocity = v3f(0,0,0);
    1147           0 :                 m_acceleration = v3f(0,0,0);
    1148           0 :                 pos_translator.vect_show = m_position;
    1149             : 
    1150           0 :                 if(m_is_local_player) // Update local player attachment position
    1151             :                 {
    1152           0 :                         LocalPlayer *player = m_env->getLocalPlayer();
    1153           0 :                         player->overridePosition = getParent()->getPosition();
    1154           0 :                         m_env->getLocalPlayer()->parent = getParent();
    1155             :                 }
    1156             :         } else {
    1157       26190 :                 v3f lastpos = pos_translator.vect_show;
    1158             : 
    1159       26190 :                 if(m_prop.physical)
    1160             :                 {
    1161        7835 :                         core::aabbox3d<f32> box = m_prop.collisionbox;
    1162        7835 :                         box.MinEdge *= BS;
    1163        7835 :                         box.MaxEdge *= BS;
    1164       15670 :                         collisionMoveResult moveresult;
    1165        7835 :                         f32 pos_max_d = BS*0.125; // Distance per iteration
    1166        7835 :                         v3f p_pos = m_position;
    1167        7835 :                         v3f p_velocity = m_velocity;
    1168        7835 :                         v3f p_acceleration = m_acceleration;
    1169       15670 :                         moveresult = collisionMoveSimple(env,env->getGameDef(),
    1170             :                                         pos_max_d, box, m_prop.stepheight, dtime,
    1171             :                                         p_pos, p_velocity, p_acceleration,
    1172       15670 :                                         this, m_prop.collideWithObjects);
    1173             :                         // Apply results
    1174        7835 :                         m_position = p_pos;
    1175        7835 :                         m_velocity = p_velocity;
    1176        7835 :                         m_acceleration = p_acceleration;
    1177             : 
    1178        7835 :                         bool is_end_position = moveresult.collides;
    1179        7835 :                         pos_translator.update(m_position, is_end_position, dtime);
    1180        7835 :                         pos_translator.translate(dtime);
    1181        7835 :                         updateNodePos();
    1182             :                 } else {
    1183       18355 :                         m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration;
    1184       18355 :                         m_velocity += dtime * m_acceleration;
    1185       36710 :                         pos_translator.update(m_position, pos_translator.aim_is_end,
    1186       18355 :                                         pos_translator.anim_time);
    1187       18355 :                         pos_translator.translate(dtime);
    1188       18355 :                         updateNodePos();
    1189             :                 }
    1190             : 
    1191       26190 :                 float moved = lastpos.getDistanceFrom(pos_translator.vect_show);
    1192       26190 :                 m_step_distance_counter += moved;
    1193       26190 :                 if(m_step_distance_counter > 1.5*BS)
    1194             :                 {
    1195         107 :                         m_step_distance_counter = 0;
    1196         107 :                         if(!m_is_local_player && m_prop.makes_footstep_sound)
    1197             :                         {
    1198          26 :                                 INodeDefManager *ndef = m_gamedef->ndef();
    1199          52 :                                 v3s16 p = floatToInt(getPosition() + v3f(0,
    1200          52 :                                                 (m_prop.collisionbox.MinEdge.Y-0.5)*BS, 0), BS);
    1201          26 :                                 MapNode n = m_env->getMap().getNodeNoEx(p);
    1202          52 :                                 SimpleSoundSpec spec = ndef->get(n).sound_footstep;
    1203          26 :                                 m_gamedef->sound()->playSoundAt(spec, false, getPosition());
    1204             :                         }
    1205             :                 }
    1206             :         }
    1207             : 
    1208       26190 :         m_anim_timer += dtime;
    1209       26190 :         if(m_anim_timer >= m_anim_framelength)
    1210             :         {
    1211        3650 :                 m_anim_timer -= m_anim_framelength;
    1212        3650 :                 m_anim_frame++;
    1213        3650 :                 if(m_anim_frame >= m_anim_num_frames)
    1214        3650 :                         m_anim_frame = 0;
    1215             :         }
    1216             : 
    1217       26190 :         updateTexturePos();
    1218             : 
    1219       26190 :         if(m_reset_textures_timer >= 0)
    1220             :         {
    1221           0 :                 m_reset_textures_timer -= dtime;
    1222           0 :                 if(m_reset_textures_timer <= 0){
    1223           0 :                         m_reset_textures_timer = -1;
    1224           0 :                         updateTextures("");
    1225             :                 }
    1226             :         }
    1227       26190 :         if(getParent() == NULL && fabs(m_prop.automatic_rotate) > 0.001)
    1228             :         {
    1229        1083 :                 m_yaw += dtime * m_prop.automatic_rotate * 180 / M_PI;
    1230        1083 :                 updateNodePos();
    1231             :         }
    1232             : 
    1233       26190 :         if (getParent() == NULL && m_prop.automatic_face_movement_dir &&
    1234           0 :                         (fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001))
    1235             :         {
    1236           0 :                 m_yaw = atan2(m_velocity.Z,m_velocity.X) * 180 / M_PI
    1237           0 :                                 + m_prop.automatic_face_movement_dir_offset;
    1238           0 :                 updateNodePos();
    1239             :         }
    1240       26190 : }
    1241             : 
    1242       26190 : void GenericCAO::updateTexturePos()
    1243             : {
    1244       26190 :         if(m_spritenode)
    1245             :         {
    1246             :                 scene::ICameraSceneNode* camera =
    1247           0 :                                 m_spritenode->getSceneManager()->getActiveCamera();
    1248           0 :                 if(!camera)
    1249           0 :                         return;
    1250           0 :                 v3f cam_to_entity = m_spritenode->getAbsolutePosition()
    1251           0 :                                 - camera->getAbsolutePosition();
    1252           0 :                 cam_to_entity.normalize();
    1253             : 
    1254           0 :                 int row = m_tx_basepos.Y;
    1255           0 :                 int col = m_tx_basepos.X;
    1256             : 
    1257           0 :                 if(m_tx_select_horiz_by_yawpitch)
    1258             :                 {
    1259           0 :                         if(cam_to_entity.Y > 0.75)
    1260           0 :                                 col += 5;
    1261           0 :                         else if(cam_to_entity.Y < -0.75)
    1262           0 :                                 col += 4;
    1263             :                         else{
    1264             :                                 float mob_dir =
    1265           0 :                                                 atan2(cam_to_entity.Z, cam_to_entity.X) / M_PI * 180.;
    1266           0 :                                 float dir = mob_dir - m_yaw;
    1267           0 :                                 dir = wrapDegrees_180(dir);
    1268             :                                 //infostream<<"id="<<m_id<<" dir="<<dir<<std::endl;
    1269           0 :                                 if(fabs(wrapDegrees_180(dir - 0)) <= 45.1)
    1270           0 :                                         col += 2;
    1271           0 :                                 else if(fabs(wrapDegrees_180(dir - 90)) <= 45.1)
    1272           0 :                                         col += 3;
    1273           0 :                                 else if(fabs(wrapDegrees_180(dir - 180)) <= 45.1)
    1274           0 :                                         col += 0;
    1275           0 :                                 else if(fabs(wrapDegrees_180(dir + 90)) <= 45.1)
    1276           0 :                                         col += 1;
    1277             :                                 else
    1278           0 :                                         col += 4;
    1279             :                         }
    1280             :                 }
    1281             : 
    1282             :                 // Animation goes downwards
    1283           0 :                 row += m_anim_frame;
    1284             : 
    1285           0 :                 float txs = m_tx_size.X;
    1286           0 :                 float tys = m_tx_size.Y;
    1287           0 :                 setBillboardTextureMatrix(m_spritenode,
    1288           0 :                                 txs, tys, col, row);
    1289             :         }
    1290             : }
    1291             : 
    1292         118 : void GenericCAO::updateTextures(const std::string &mod)
    1293             : {
    1294         118 :         ITextureSource *tsrc = m_gamedef->tsrc();
    1295             : 
    1296         118 :         bool use_trilinear_filter = g_settings->getBool("trilinear_filter");
    1297         118 :         bool use_bilinear_filter = g_settings->getBool("bilinear_filter");
    1298         118 :         bool use_anisotropic_filter = g_settings->getBool("anisotropic_filter");
    1299             : 
    1300         118 :         if(m_spritenode)
    1301             :         {
    1302           0 :                 if(m_prop.visual == "sprite")
    1303             :                 {
    1304           0 :                         std::string texturestring = "unknown_node.png";
    1305           0 :                         if(m_prop.textures.size() >= 1)
    1306           0 :                                 texturestring = m_prop.textures[0];
    1307           0 :                         texturestring += mod;
    1308           0 :                         m_spritenode->setMaterialTexture(0,
    1309           0 :                                         tsrc->getTextureForMesh(texturestring));
    1310             : 
    1311             :                         // This allows setting per-material colors. However, until a real lighting
    1312             :                         // system is added, the code below will have no effect. Once MineTest
    1313             :                         // has directional lighting, it should work automatically.
    1314           0 :                         if(m_prop.colors.size() >= 1)
    1315             :                         {
    1316           0 :                                 m_spritenode->getMaterial(0).AmbientColor = m_prop.colors[0];
    1317           0 :                                 m_spritenode->getMaterial(0).DiffuseColor = m_prop.colors[0];
    1318           0 :                                 m_spritenode->getMaterial(0).SpecularColor = m_prop.colors[0];
    1319             :                         }
    1320             : 
    1321           0 :                         m_spritenode->getMaterial(0).setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
    1322           0 :                         m_spritenode->getMaterial(0).setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
    1323           0 :                         m_spritenode->getMaterial(0).setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
    1324             :                 }
    1325             :         }
    1326         118 :         if(m_animated_meshnode)
    1327             :         {
    1328          26 :                 if(m_prop.visual == "mesh")
    1329             :                 {
    1330         130 :                         for (u32 i = 0; i < m_prop.textures.size() &&
    1331          52 :                                         i < m_animated_meshnode->getMaterialCount(); ++i)
    1332             :                         {
    1333         104 :                                 std::string texturestring = m_prop.textures[i];
    1334          52 :                                 if(texturestring == "")
    1335           0 :                                         continue; // Empty texture string means don't modify that material
    1336          52 :                                 texturestring += mod;
    1337          52 :                                 video::ITexture* texture = tsrc->getTextureForMesh(texturestring);
    1338          52 :                                 if(!texture)
    1339             :                                 {
    1340           0 :                                         errorstream<<"GenericCAO::updateTextures(): Could not load texture "<<texturestring<<std::endl;
    1341           0 :                                         continue;
    1342             :                                 }
    1343             : 
    1344             :                                 // Set material flags and texture
    1345          52 :                                 video::SMaterial& material = m_animated_meshnode->getMaterial(i);
    1346          52 :                                 material.TextureLayer[0].Texture = texture;
    1347          52 :                                 material.setFlag(video::EMF_LIGHTING, false);
    1348          52 :                                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
    1349             : 
    1350         104 :                                 m_animated_meshnode->getMaterial(i)
    1351         156 :                                                 .setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
    1352         104 :                                 m_animated_meshnode->getMaterial(i)
    1353         156 :                                                 .setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
    1354         104 :                                 m_animated_meshnode->getMaterial(i)
    1355         156 :                                                 .setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
    1356             :                         }
    1357         111 :                         for (u32 i = 0; i < m_prop.colors.size() &&
    1358          52 :                         i < m_animated_meshnode->getMaterialCount(); ++i)
    1359             :                         {
    1360             :                                 // This allows setting per-material colors. However, until a real lighting
    1361             :                                 // system is added, the code below will have no effect. Once MineTest
    1362             :                                 // has directional lighting, it should work automatically.
    1363          33 :                                 m_animated_meshnode->getMaterial(i).AmbientColor = m_prop.colors[i];
    1364          33 :                                 m_animated_meshnode->getMaterial(i).DiffuseColor = m_prop.colors[i];
    1365          33 :                                 m_animated_meshnode->getMaterial(i).SpecularColor = m_prop.colors[i];
    1366             :                         }
    1367             :                 }
    1368             :         }
    1369         118 :         if(m_meshnode)
    1370             :         {
    1371          67 :                 if(m_prop.visual == "cube")
    1372             :                 {
    1373           0 :                         for (u32 i = 0; i < 6; ++i)
    1374             :                         {
    1375           0 :                                 std::string texturestring = "unknown_node.png";
    1376           0 :                                 if(m_prop.textures.size() > i)
    1377           0 :                                         texturestring = m_prop.textures[i];
    1378           0 :                                 texturestring += mod;
    1379             : 
    1380             : 
    1381             :                                 // Set material flags and texture
    1382           0 :                                 video::SMaterial& material = m_meshnode->getMaterial(i);
    1383           0 :                                 material.setFlag(video::EMF_LIGHTING, false);
    1384           0 :                                 material.setFlag(video::EMF_BILINEAR_FILTER, false);
    1385           0 :                                 material.setTexture(0,
    1386           0 :                                                 tsrc->getTextureForMesh(texturestring));
    1387           0 :                                 material.getTextureMatrix(0).makeIdentity();
    1388             : 
    1389             :                                 // This allows setting per-material colors. However, until a real lighting
    1390             :                                 // system is added, the code below will have no effect. Once MineTest
    1391             :                                 // has directional lighting, it should work automatically.
    1392           0 :                                 if(m_prop.colors.size() > i)
    1393             :                                 {
    1394           0 :                                         m_meshnode->getMaterial(i).AmbientColor = m_prop.colors[i];
    1395           0 :                                         m_meshnode->getMaterial(i).DiffuseColor = m_prop.colors[i];
    1396           0 :                                         m_meshnode->getMaterial(i).SpecularColor = m_prop.colors[i];
    1397             :                                 }
    1398             : 
    1399           0 :                                 m_meshnode->getMaterial(i).setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
    1400           0 :                                 m_meshnode->getMaterial(i).setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
    1401           0 :                                 m_meshnode->getMaterial(i).setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
    1402             :                         }
    1403             :                 }
    1404          67 :                 else if(m_prop.visual == "upright_sprite")
    1405             :                 {
    1406          67 :                         scene::IMesh *mesh = m_meshnode->getMesh();
    1407             :                         {
    1408         134 :                                 std::string tname = "unknown_object.png";
    1409          67 :                                 if(m_prop.textures.size() >= 1)
    1410          67 :                                         tname = m_prop.textures[0];
    1411          67 :                                 tname += mod;
    1412          67 :                                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(0);
    1413          67 :                                 buf->getMaterial().setTexture(0,
    1414         134 :                                                 tsrc->getTextureForMesh(tname));
    1415             : 
    1416             :                                 // This allows setting per-material colors. However, until a real lighting
    1417             :                                 // system is added, the code below will have no effect. Once MineTest
    1418             :                                 // has directional lighting, it should work automatically.
    1419          67 :                                 if(m_prop.colors.size() >= 1)
    1420             :                                 {
    1421          67 :                                         buf->getMaterial().AmbientColor = m_prop.colors[0];
    1422          67 :                                         buf->getMaterial().DiffuseColor = m_prop.colors[0];
    1423          67 :                                         buf->getMaterial().SpecularColor = m_prop.colors[0];
    1424             :                                 }
    1425             : 
    1426          67 :                                 buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
    1427          67 :                                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
    1428          67 :                                 buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
    1429             :                         }
    1430             :                         {
    1431         134 :                                 std::string tname = "unknown_object.png";
    1432          67 :                                 if(m_prop.textures.size() >= 2)
    1433           0 :                                         tname = m_prop.textures[1];
    1434          67 :                                 else if(m_prop.textures.size() >= 1)
    1435          67 :                                         tname = m_prop.textures[0];
    1436          67 :                                 tname += mod;
    1437          67 :                                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(1);
    1438          67 :                                 buf->getMaterial().setTexture(0,
    1439         134 :                                                 tsrc->getTextureForMesh(tname));
    1440             : 
    1441             :                                 // This allows setting per-material colors. However, until a real lighting
    1442             :                                 // system is added, the code below will have no effect. Once MineTest
    1443             :                                 // has directional lighting, it should work automatically.
    1444          67 :                                 if(m_prop.colors.size() >= 2)
    1445             :                                 {
    1446          67 :                                         buf->getMaterial().AmbientColor = m_prop.colors[1];
    1447          67 :                                         buf->getMaterial().DiffuseColor = m_prop.colors[1];
    1448          67 :                                         buf->getMaterial().SpecularColor = m_prop.colors[1];
    1449             :                                 }
    1450           0 :                                 else if(m_prop.colors.size() >= 1)
    1451             :                                 {
    1452           0 :                                         buf->getMaterial().AmbientColor = m_prop.colors[0];
    1453           0 :                                         buf->getMaterial().DiffuseColor = m_prop.colors[0];
    1454           0 :                                         buf->getMaterial().SpecularColor = m_prop.colors[0];
    1455             :                                 }
    1456             : 
    1457          67 :                                 buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
    1458          67 :                                 buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
    1459          67 :                                 buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
    1460             :                         }
    1461             :                 }
    1462             :         }
    1463         118 : }
    1464             : 
    1465         304 : void GenericCAO::updateAnimation()
    1466             : {
    1467         304 :         if(m_animated_meshnode == NULL)
    1468         162 :                 return;
    1469             : 
    1470         211 :         if (m_animated_meshnode->getStartFrame() != m_animation_range.X ||
    1471          69 :                 m_animated_meshnode->getEndFrame() != m_animation_range.Y)
    1472          98 :                         m_animated_meshnode->setFrameLoop(m_animation_range.X, m_animation_range.Y);
    1473         142 :         if (m_animated_meshnode->getAnimationSpeed() != m_animation_speed)
    1474         134 :                 m_animated_meshnode->setAnimationSpeed(m_animation_speed);
    1475         142 :         m_animated_meshnode->setTransitionTime(m_animation_blend);
    1476             : // Requires Irrlicht 1.8 or greater
    1477             : #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR > 1
    1478         142 :         if (m_animated_meshnode->getLoopMode() != m_animation_loop)
    1479           0 :                 m_animated_meshnode->setLoopMode(m_animation_loop);
    1480             : #endif
    1481             : }
    1482             : 
    1483         118 : void GenericCAO::updateBonePosition()
    1484             : {
    1485         118 :         if(m_bone_position.empty() || m_animated_meshnode == NULL)
    1486         118 :                 return;
    1487             : 
    1488           0 :         m_animated_meshnode->setJointMode(irr::scene::EJUOR_CONTROL); // To write positions to the mesh on render
    1489           0 :         for(std::map<std::string,
    1490           0 :                         core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin();
    1491           0 :                         ii != m_bone_position.end(); ++ii)
    1492             :         {
    1493           0 :                 std::string bone_name = (*ii).first;
    1494           0 :                 v3f bone_pos = (*ii).second.X;
    1495           0 :                 v3f bone_rot = (*ii).second.Y;
    1496           0 :                 irr::scene::IBoneSceneNode* bone = m_animated_meshnode->getJointNode(bone_name.c_str());
    1497           0 :                 if(bone)
    1498             :                 {
    1499           0 :                         bone->setPosition(bone_pos);
    1500           0 :                         bone->setRotation(bone_rot);
    1501             :                 }
    1502             :         }
    1503             : }
    1504             : 
    1505         197 : void GenericCAO::updateAttachments()
    1506             : {
    1507             : 
    1508         197 :         if (getParent() == NULL) { // Detach or don't attach
    1509         197 :                 scene::ISceneNode *node = getSceneNode();
    1510         197 :                 if (node) {
    1511         153 :                         v3f old_position = node->getAbsolutePosition();
    1512         153 :                         v3f old_rotation = node->getRotation();
    1513         153 :                         node->setParent(m_smgr->getRootSceneNode());
    1514         153 :                         node->setPosition(old_position);
    1515         153 :                         node->setRotation(old_rotation);
    1516         153 :                         node->updateAbsolutePosition();
    1517             :                 }
    1518         197 :                 if (m_is_local_player) {
    1519           6 :                         LocalPlayer *player = m_env->getLocalPlayer();
    1520           6 :                         player->isAttached = false;
    1521             :                 }
    1522             :         }
    1523             :         else // Attach
    1524             :         {
    1525           0 :                 scene::ISceneNode *my_node = getSceneNode();
    1526             : 
    1527           0 :                 scene::ISceneNode *parent_node = getParent()->getSceneNode();
    1528             :                 scene::IAnimatedMeshSceneNode *parent_animated_mesh_node =
    1529           0 :                                 getParent()->getAnimatedMeshSceneNode();
    1530           0 :                 if (parent_animated_mesh_node && m_attachment_bone != "") {
    1531           0 :                         parent_node = parent_animated_mesh_node->getJointNode(m_attachment_bone.c_str());
    1532             :                 }
    1533             : 
    1534           0 :                 if (my_node && parent_node) {
    1535           0 :                         my_node->setParent(parent_node);
    1536           0 :                         my_node->setPosition(m_attachment_position);
    1537           0 :                         my_node->setRotation(m_attachment_rotation);
    1538           0 :                         my_node->updateAbsolutePosition();
    1539             :                 }
    1540           0 :                 if (m_is_local_player) {
    1541           0 :                         LocalPlayer *player = m_env->getLocalPlayer();
    1542           0 :                         player->isAttached = true;
    1543             :                 }
    1544             :         }
    1545         197 : }
    1546             : 
    1547        1640 : void GenericCAO::processMessage(const std::string &data)
    1548             : {
    1549             :         //infostream<<"GenericCAO: Got message"<<std::endl;
    1550        3280 :         std::istringstream is(data, std::ios::binary);
    1551             :         // command
    1552        1640 :         u8 cmd = readU8(is);
    1553        1640 :         if(cmd == GENERIC_CMD_SET_PROPERTIES)
    1554             :         {
    1555         118 :                 m_prop = gob_read_set_properties(is);
    1556             : 
    1557         118 :                 m_selection_box = m_prop.collisionbox;
    1558         118 :                 m_selection_box.MinEdge *= BS;
    1559         118 :                 m_selection_box.MaxEdge *= BS;
    1560             : 
    1561         118 :                 m_tx_size.X = 1.0 / m_prop.spritediv.X;
    1562         118 :                 m_tx_size.Y = 1.0 / m_prop.spritediv.Y;
    1563             : 
    1564         118 :                 if(!m_initial_tx_basepos_set){
    1565          44 :                         m_initial_tx_basepos_set = true;
    1566          44 :                         m_tx_basepos = m_prop.initial_sprite_basepos;
    1567             :                 }
    1568             : 
    1569         118 :                 expireVisuals();
    1570             :         }
    1571        1522 :         else if(cmd == GENERIC_CMD_UPDATE_POSITION)
    1572             :         {
    1573             :                 // Not sent by the server if this object is an attachment.
    1574             :                 // We might however get here if the server notices the object being detached before the client.
    1575        1163 :                 m_position = readV3F1000(is);
    1576        1163 :                 m_velocity = readV3F1000(is);
    1577        1163 :                 m_acceleration = readV3F1000(is);
    1578        1163 :                 if(fabs(m_prop.automatic_rotate) < 0.001)
    1579        1117 :                         m_yaw = readF1000(is);
    1580             :                 else
    1581          46 :                         readF1000(is);
    1582        1163 :                 bool do_interpolate = readU8(is);
    1583        1163 :                 bool is_end_position = readU8(is);
    1584        1163 :                 float update_interval = readF1000(is);
    1585             : 
    1586             :                 // Place us a bit higher if we're physical, to not sink into
    1587             :                 // the ground due to sucky collision detection...
    1588        1163 :                 if(m_prop.physical)
    1589         923 :                         m_position += v3f(0,0.002,0);
    1590             : 
    1591        1163 :                 if(getParent() != NULL) // Just in case
    1592           0 :                         return;
    1593             : 
    1594        1163 :                 if(do_interpolate)
    1595             :                 {
    1596        1158 :                         if(!m_prop.physical)
    1597         235 :                                 pos_translator.update(m_position, is_end_position, update_interval);
    1598             :                 } else {
    1599           5 :                         pos_translator.init(m_position);
    1600             :                 }
    1601        1163 :                 updateNodePos();
    1602             :         }
    1603         359 :         else if(cmd == GENERIC_CMD_SET_TEXTURE_MOD) {
    1604           0 :                 std::string mod = deSerializeString(is);
    1605           0 :                 updateTextures(mod);
    1606             :         }
    1607         359 :         else if(cmd == GENERIC_CMD_SET_SPRITE) {
    1608           0 :                 v2s16 p = readV2S16(is);
    1609           0 :                 int num_frames = readU16(is);
    1610           0 :                 float framelength = readF1000(is);
    1611           0 :                 bool select_horiz_by_yawpitch = readU8(is);
    1612             : 
    1613           0 :                 m_tx_basepos = p;
    1614           0 :                 m_anim_num_frames = num_frames;
    1615           0 :                 m_anim_framelength = framelength;
    1616           0 :                 m_tx_select_horiz_by_yawpitch = select_horiz_by_yawpitch;
    1617             : 
    1618           0 :                 updateTexturePos();
    1619             :         }
    1620         359 :         else if(cmd == GENERIC_CMD_SET_PHYSICS_OVERRIDE) {
    1621           3 :                 float override_speed = readF1000(is);
    1622           3 :                 float override_jump = readF1000(is);
    1623           3 :                 float override_gravity = readF1000(is);
    1624             :                 // these are sent inverted so we get true when the server sends nothing
    1625           3 :                 bool sneak = !readU8(is);
    1626           3 :                 bool sneak_glitch = !readU8(is);
    1627             : 
    1628             : 
    1629           3 :                 if(m_is_local_player)
    1630             :                 {
    1631           2 :                         LocalPlayer *player = m_env->getLocalPlayer();
    1632           2 :                         player->physics_override_speed = override_speed;
    1633           2 :                         player->physics_override_jump = override_jump;
    1634           2 :                         player->physics_override_gravity = override_gravity;
    1635           2 :                         player->physics_override_sneak = sneak;
    1636           2 :                         player->physics_override_sneak_glitch = sneak_glitch;
    1637             :                 }
    1638             :         }
    1639         356 :         else if(cmd == GENERIC_CMD_SET_ANIMATION) {
    1640             :                 // TODO: change frames send as v2s32 value
    1641         196 :                 v2f range = readV2F1000(is);
    1642         196 :                 if (!m_is_local_player) {
    1643         175 :                         m_animation_range = v2s32((s32)range.X, (s32)range.Y);
    1644         175 :                         m_animation_speed = readF1000(is);
    1645         175 :                         m_animation_blend = readF1000(is);
    1646             :                         // these are sent inverted so we get true when the server sends nothing
    1647         175 :                         m_animation_loop = !readU8(is);
    1648         175 :                         updateAnimation();
    1649             :                 } else {
    1650          21 :                         LocalPlayer *player = m_env->getLocalPlayer();
    1651          21 :                         if(player->last_animation == NO_ANIM)
    1652             :                         {
    1653          21 :                                 m_animation_range = v2s32((s32)range.X, (s32)range.Y);
    1654          21 :                                 m_animation_speed = readF1000(is);
    1655          21 :                                 m_animation_blend = readF1000(is);
    1656             :                                 // these are sent inverted so we get true when the server sends nothing
    1657          21 :                                 m_animation_loop = !readU8(is);
    1658             :                         }
    1659             :                         // update animation only if local animations present
    1660             :                         // and received animation is unknown (except idle animation)
    1661          21 :                         bool is_known = false;
    1662          84 :                         for (int i = 1;i<4;i++)
    1663             :                         {
    1664          63 :                                 if(m_animation_range.Y == player->local_animations[i].Y)
    1665          10 :                                         is_known = true;
    1666             :                         }
    1667          31 :                         if(!is_known ||
    1668          10 :                                         (player->local_animations[1].Y + player->local_animations[2].Y < 1))
    1669             :                         {
    1670          11 :                                         updateAnimation();
    1671             :                         }
    1672             :                 }
    1673             :         }
    1674         160 :         else if(cmd == GENERIC_CMD_SET_BONE_POSITION) {
    1675           0 :                 std::string bone = deSerializeString(is);
    1676           0 :                 v3f position = readV3F1000(is);
    1677           0 :                 v3f rotation = readV3F1000(is);
    1678           0 :                 m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
    1679             : 
    1680           0 :                 updateBonePosition();
    1681         160 :         } else if (cmd == GENERIC_CMD_ATTACH_TO) {
    1682          79 :                 u16 parentID = readS16(is);
    1683          79 :                 u16 oldparent = m_env->attachement_parent_ids[getId()];
    1684          79 :                 if (oldparent) {
    1685             :                         m_children.erase(std::remove(m_children.begin(), m_children.end(),
    1686           0 :                                 getId()), m_children.end());
    1687             :                 }
    1688          79 :                 m_env->attachement_parent_ids[getId()] = parentID;
    1689          79 :                 GenericCAO *parentobj = m_env->getGenericCAO(parentID);
    1690             : 
    1691          79 :                 if (parentobj) {
    1692           0 :                         parentobj->m_children.push_back(getId());
    1693             :                 }
    1694             : 
    1695          79 :                 m_attachment_bone = deSerializeString(is);
    1696          79 :                 m_attachment_position = readV3F1000(is);
    1697          79 :                 m_attachment_rotation = readV3F1000(is);
    1698             : 
    1699             :                 // localplayer itself can't be attached to localplayer
    1700          79 :                 if (!m_is_local_player) {
    1701          78 :                         m_attached_to_local = getParent() != NULL && getParent()->isLocalPlayer();
    1702             :                         // Objects attached to the local player should be hidden by default
    1703          78 :                         m_is_visible = !m_attached_to_local;
    1704             :                 }
    1705             : 
    1706          79 :                 updateAttachments();
    1707             :         }
    1708          81 :         else if(cmd == GENERIC_CMD_PUNCHED) {
    1709           1 :                 /*s16 damage =*/ readS16(is);
    1710           1 :                 s16 result_hp = readS16(is);
    1711             : 
    1712             :                 // Use this instead of the send damage to not interfere with prediction
    1713           1 :                 s16 damage = m_hp - result_hp;
    1714             : 
    1715           1 :                 m_hp = result_hp;
    1716             : 
    1717           1 :                 if (damage > 0)
    1718             :                 {
    1719           0 :                         if (m_hp <= 0)
    1720             :                         {
    1721             :                                 // TODO: Execute defined fast response
    1722             :                                 // As there is no definition, make a smoke puff
    1723           0 :                                 ClientSimpleObject *simple = createSmokePuff(
    1724             :                                                 m_smgr, m_env, m_position,
    1725           0 :                                                 m_prop.visual_size * BS);
    1726           0 :                                 m_env->addSimpleObject(simple);
    1727             :                         } else {
    1728             :                                 // TODO: Execute defined fast response
    1729             :                                 // Flashing shall suffice as there is no definition
    1730           0 :                                 m_reset_textures_timer = 0.05;
    1731           0 :                                 if(damage >= 2)
    1732           0 :                                         m_reset_textures_timer += 0.05 * damage;
    1733           0 :                                 updateTextures("^[brighten");
    1734             :                         }
    1735             :                 }
    1736             :         }
    1737          80 :         else if(cmd == GENERIC_CMD_UPDATE_ARMOR_GROUPS) {
    1738          80 :                 m_armor_groups.clear();
    1739          80 :                 int armor_groups_size = readU16(is);
    1740         161 :                 for(int i=0; i<armor_groups_size; i++)
    1741             :                 {
    1742         162 :                         std::string name = deSerializeString(is);
    1743          81 :                         int rating = readS16(is);
    1744          81 :                         m_armor_groups[name] = rating;
    1745             :                 }
    1746           0 :         } else if (cmd == GENERIC_CMD_UPDATE_NAMETAG_ATTRIBUTES) {
    1747           0 :                 readU8(is); // version
    1748           0 :                 m_nametag_color = readARGB8(is);
    1749           0 :                 if (m_textnode != NULL) {
    1750           0 :                         m_textnode->setTextColor(m_nametag_color);
    1751             : 
    1752             :                         // Enforce hiding nametag,
    1753             :                         // because if freetype is enabled, a grey
    1754             :                         // shadow can remain.
    1755           0 :                         m_textnode->setVisible(m_nametag_color.getAlpha() > 0);
    1756             :                 }
    1757             :         }
    1758             : }
    1759             : 
    1760             : /* \pre punchitem != NULL
    1761             :  */
    1762           0 : bool GenericCAO::directReportPunch(v3f dir, const ItemStack *punchitem,
    1763             :                 float time_from_last_punch)
    1764             : {
    1765             :         assert(punchitem);      // pre-condition
    1766             :         const ToolCapabilities *toolcap =
    1767           0 :                         &punchitem->getToolCapabilities(m_gamedef->idef());
    1768             :         PunchDamageResult result = getPunchDamage(
    1769             :                         m_armor_groups,
    1770             :                         toolcap,
    1771             :                         punchitem,
    1772           0 :                         time_from_last_punch);
    1773             : 
    1774           0 :         if(result.did_punch && result.damage != 0)
    1775             :         {
    1776           0 :                 if(result.damage < m_hp)
    1777             :                 {
    1778           0 :                         m_hp -= result.damage;
    1779             :                 } else {
    1780           0 :                         m_hp = 0;
    1781             :                         // TODO: Execute defined fast response
    1782             :                         // As there is no definition, make a smoke puff
    1783           0 :                         ClientSimpleObject *simple = createSmokePuff(
    1784             :                                         m_smgr, m_env, m_position,
    1785           0 :                                         m_prop.visual_size * BS);
    1786           0 :                         m_env->addSimpleObject(simple);
    1787             :                 }
    1788             :                 // TODO: Execute defined fast response
    1789             :                 // Flashing shall suffice as there is no definition
    1790           0 :                 m_reset_textures_timer = 0.05;
    1791           0 :                 if(result.damage >= 2)
    1792           0 :                         m_reset_textures_timer += 0.05 * result.damage;
    1793           0 :                 updateTextures("^[brighten");
    1794             :         }
    1795             : 
    1796           0 :         return false;
    1797             : }
    1798             : 
    1799           0 : std::string GenericCAO::debugInfoText()
    1800             : {
    1801           0 :         std::ostringstream os(std::ios::binary);
    1802           0 :         os<<"GenericCAO hp="<<m_hp<<"\n";
    1803           0 :         os<<"armor={";
    1804           0 :         for(ItemGroupList::const_iterator i = m_armor_groups.begin();
    1805           0 :                         i != m_armor_groups.end(); i++)
    1806             :         {
    1807           0 :                 os<<i->first<<"="<<i->second<<", ";
    1808             :         }
    1809           0 :         os<<"}";
    1810           0 :         return os.str();
    1811             : }
    1812             : 
    1813             : // Prototype
    1814           3 : GenericCAO proto_GenericCAO(NULL, NULL);

Generated by: LCOV version 1.11