3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
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"
34 #include "serialization.h" // For decompressZlib
36 #include "clientobject.h"
40 #include "content_cso.h"
43 #include "localplayer.h"
45 #include "camera.h" // CameraModes
46 #include "wieldmesh.h"
50 struct ToolCapabilities
;
52 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
54 std::map
<u16
, ClientActiveObject::Factory
> ClientActiveObject::m_types
;
56 SmoothTranslator::SmoothTranslator():
66 void SmoothTranslator::init(v3f vect
)
73 anim_time_counter
= 0;
77 void SmoothTranslator::sharpen()
82 void SmoothTranslator::update(v3f vect_new
, bool is_end_position
, float update_interval
)
84 aim_is_end
= is_end_position
;
87 if(update_interval
> 0)
89 anim_time
= update_interval
;
91 if(anim_time
< 0.001 || anim_time
> 1.0)
92 anim_time
= anim_time_counter
;
94 anim_time
= anim_time
* 0.9 + anim_time_counter
* 0.1;
96 anim_time_counter
= 0;
100 void SmoothTranslator::translate(f32 dtime
)
102 anim_time_counter
= anim_time_counter
+ dtime
;
103 anim_counter
= anim_counter
+ dtime
;
104 v3f vect_move
= vect_aim
- vect_old
;
106 if(anim_time
> 0.001)
107 moveratio
= anim_time_counter
/ anim_time
;
108 // Move a bit less than should, to avoid oscillation
109 moveratio
= moveratio
* 0.8;
110 float move_end
= 1.5;
113 if(moveratio
> move_end
)
114 moveratio
= move_end
;
115 vect_show
= vect_old
+ vect_move
* moveratio
;
118 bool SmoothTranslator::is_moving()
120 return ((anim_time_counter
/ anim_time
) < 1.4);
127 static void setBillboardTextureMatrix(scene::IBillboardSceneNode
*bill
,
128 float txs
, float tys
, int col
, int row
)
130 video::SMaterial
& material
= bill
->getMaterial(0);
131 core::matrix4
& matrix
= material
.getTextureMatrix(0);
132 matrix
.setTextureTranslate(txs
*col
, tys
*row
);
133 matrix
.setTextureScale(txs
, tys
);
140 class TestCAO
: public ClientActiveObject
143 TestCAO(IGameDef
*gamedef
, ClientEnvironment
*env
);
146 ActiveObjectType
getType() const
148 return ACTIVEOBJECT_TYPE_TEST
;
151 static ClientActiveObject
* create(IGameDef
*gamedef
, ClientEnvironment
*env
);
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();
160 void step(float dtime
, ClientEnvironment
*env
);
162 void processMessage(const std::string
&data
);
164 bool getCollisionBox(aabb3f
*toset
) { return false; }
166 scene::IMeshSceneNode
*m_node
;
171 TestCAO
proto_TestCAO(NULL
, NULL
);
173 TestCAO::TestCAO(IGameDef
*gamedef
, ClientEnvironment
*env
):
174 ClientActiveObject(0, gamedef
, env
),
176 m_position(v3f(0,10*BS
,0))
178 ClientActiveObject::registerType(getType(), create
);
185 ClientActiveObject
* TestCAO::create(IGameDef
*gamedef
, ClientEnvironment
*env
)
187 return new TestCAO(gamedef
, env
);
190 void TestCAO::addToScene(scene::ISceneManager
*smgr
, ITextureSource
*tsrc
,
196 //video::IVideoDriver* driver = smgr->getVideoDriver();
198 scene::SMesh
*mesh
= new scene::SMesh();
199 scene::IMeshBuffer
*buf
= new scene::SMeshBuffer();
200 video::SColor
c(255,255,255,255);
201 video::S3DVertex vertices
[4] =
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),
208 u16 indices
[] = {0,1,2,2,3,0};
209 buf
->append(vertices
, 4, indices
, 6);
211 buf
->getMaterial().setFlag(video::EMF_LIGHTING
, false);
212 buf
->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING
, false);
213 buf
->getMaterial().setTexture(0, tsrc
->getTextureForMesh("rat.png"));
214 buf
->getMaterial().setFlag(video::EMF_BILINEAR_FILTER
, false);
215 buf
->getMaterial().setFlag(video::EMF_FOG_ENABLE
, true);
216 buf
->getMaterial().MaterialType
= video::EMT_TRANSPARENT_ALPHA_CHANNEL
;
218 mesh
->addMeshBuffer(buf
);
220 m_node
= smgr
->addMeshSceneNode(mesh
, NULL
);
225 void TestCAO::removeFromScene(bool permanent
)
234 void TestCAO::updateLight(u8 light_at_pos
)
238 v3s16
TestCAO::getLightPosition()
240 return floatToInt(m_position
, BS
);
243 void TestCAO::updateNodePos()
248 m_node
->setPosition(m_position
);
249 //m_node->setRotation(v3f(0, 45, 0));
252 void TestCAO::step(float dtime
, ClientEnvironment
*env
)
256 v3f rot
= m_node
->getRotation();
257 //infostream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
258 rot
.Y
+= dtime
* 180;
259 m_node
->setRotation(rot
);
263 void TestCAO::processMessage(const std::string
&data
)
265 infostream
<<"TestCAO: Got data: "<<data
<<std::endl
;
266 std::istringstream
is(data
, std::ios::binary
);
284 class ItemCAO
: public ClientActiveObject
287 ItemCAO(IGameDef
*gamedef
, ClientEnvironment
*env
);
290 ActiveObjectType
getType() const
292 return ACTIVEOBJECT_TYPE_ITEM
;
295 static ClientActiveObject
* create(IGameDef
*gamedef
, ClientEnvironment
*env
);
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();
306 void step(float dtime
, ClientEnvironment
*env
);
308 void processMessage(const std::string
&data
);
310 void initialize(const std::string
&data
);
312 core::aabbox3d
<f32
>* getSelectionBox()
313 {return &m_selection_box
;}
317 std::string
infoText()
320 bool getCollisionBox(aabb3f
*toset
) { return false; }
322 core::aabbox3d
<f32
> m_selection_box
;
323 scene::IMeshSceneNode
*m_node
;
325 std::string m_itemstring
;
326 std::string m_infotext
;
329 #include "inventory.h"
332 ItemCAO
proto_ItemCAO(NULL
, NULL
);
334 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.),
338 m_position(v3f(0,10*BS
,0))
342 ClientActiveObject::registerType(getType(), create
);
350 ClientActiveObject
* ItemCAO::create(IGameDef
*gamedef
, ClientEnvironment
*env
)
352 return new ItemCAO(gamedef
, env
);
355 void ItemCAO::addToScene(scene::ISceneManager
*smgr
, ITextureSource
*tsrc
,
361 //video::IVideoDriver* driver = smgr->getVideoDriver();
363 scene::SMesh
*mesh
= new scene::SMesh();
364 scene::IMeshBuffer
*buf
= new scene::SMeshBuffer();
365 video::SColor
c(255,255,255,255);
366 video::S3DVertex vertices
[4] =
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),
377 u16 indices
[] = {0,1,2,2,3,0};
378 buf
->append(vertices
, 4, indices
, 6);
380 buf
->getMaterial().setFlag(video::EMF_LIGHTING
, false);
381 buf
->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING
, false);
382 // Initialize with a generated placeholder texture
383 buf
->getMaterial().setTexture(0, tsrc
->getTexture(""));
384 buf
->getMaterial().setFlag(video::EMF_BILINEAR_FILTER
, false);
385 buf
->getMaterial().setFlag(video::EMF_FOG_ENABLE
, true);
386 buf
->getMaterial().MaterialType
= video::EMT_TRANSPARENT_ALPHA_CHANNEL
;
388 mesh
->addMeshBuffer(buf
);
390 m_node
= smgr
->addMeshSceneNode(mesh
, NULL
);
401 void ItemCAO::removeFromScene(bool permanent
)
410 void ItemCAO::updateLight(u8 light_at_pos
)
415 u8 li
= decode_light(light_at_pos
);
416 video::SColor
color(255,li
,li
,li
);
417 setMeshColor(m_node
->getMesh(), color
);
420 v3s16
ItemCAO::getLightPosition()
422 return floatToInt(m_position
+ v3f(0,0.5*BS
,0), BS
);
425 void ItemCAO::updateNodePos()
430 m_node
->setPosition(m_position
);
433 void ItemCAO::updateInfoText()
436 IItemDefManager
*idef
= m_gamedef
->idef();
438 item
.deSerialize(m_itemstring
, idef
);
439 if(item
.isKnown(idef
))
440 m_infotext
= item
.getDefinition(idef
).description
;
442 m_infotext
= "Unknown item: '" + m_itemstring
+ "'";
444 m_infotext
+= " (" + itos(item
.count
) + ")";
446 catch(SerializationError
&e
)
448 m_infotext
= "Unknown item: '" + m_itemstring
+ "'";
452 void ItemCAO::updateTexture()
457 // Create an inventory item to see what is its image
458 std::istringstream
is(m_itemstring
, std::ios_base::binary
);
459 video::ITexture
*texture
= NULL
;
461 IItemDefManager
*idef
= m_gamedef
->idef();
463 item
.deSerialize(is
, idef
);
464 texture
= idef
->getInventoryTexture(item
.getDefinition(idef
).name
, m_gamedef
);
466 catch(SerializationError
&e
)
468 warningstream
<<FUNCTION_NAME
469 <<": error deSerializing itemstring \""
470 <<m_itemstring
<<std::endl
;
473 // Set meshbuffer texture
474 m_node
->getMaterial(0).setTexture(0, texture
);
478 void ItemCAO::step(float dtime
, ClientEnvironment
*env
)
482 /*v3f rot = m_node->getRotation();
483 rot.Y += dtime * 120;
484 m_node->setRotation(rot);*/
485 LocalPlayer
*player
= env
->getLocalPlayer();
487 v3f rot
= m_node
->getRotation();
488 rot
.Y
= 180.0 - (player
->getYaw());
489 m_node
->setRotation(rot
);
493 void ItemCAO::processMessage(const std::string
&data
)
495 //infostream<<"ItemCAO: Got message"<<std::endl;
496 std::istringstream
is(data
, std::ios::binary
);
502 m_position
= readV3F1000(is
);
508 m_itemstring
= deSerializeString(is
);
514 void ItemCAO::initialize(const std::string
&data
)
516 infostream
<<"ItemCAO: Got init data"<<std::endl
;
519 std::istringstream
is(data
, std::ios::binary
);
521 u8 version
= readU8(is
);
526 m_position
= readV3F1000(is
);
528 m_itemstring
= deSerializeString(is
);
539 #include "genericobject.h"
541 GenericCAO::GenericCAO(IGameDef
*gamedef
, ClientEnvironment
*env
):
542 ClientActiveObject(0, gamedef
, env
),
545 m_is_local_player(false),
549 m_selection_box(-BS
/3.,-BS
/3.,-BS
/3., BS
/3.,BS
/3.,BS
/3.),
551 m_animated_meshnode(NULL
),
552 m_wield_meshnode(NULL
),
554 m_nametag_color(video::SColor(255, 255, 255, 255)),
556 m_position(v3f(0,10*BS
,0)),
557 m_velocity(v3f(0,0,0)),
558 m_acceleration(v3f(0,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),
575 m_anim_num_frames(1),
576 m_anim_framelength(0.2),
578 m_reset_textures_timer(-1),
579 m_visuals_expired(false),
580 m_step_distance_counter(0),
585 ClientActiveObject::registerType(getType(), create
);
588 bool GenericCAO::getCollisionBox(aabb3f
*toset
)
592 //update collision box
593 toset
->MinEdge
= m_prop
.collisionbox
.MinEdge
* BS
;
594 toset
->MaxEdge
= m_prop
.collisionbox
.MaxEdge
* BS
;
596 toset
->MinEdge
+= m_position
;
597 toset
->MaxEdge
+= m_position
;
605 bool GenericCAO::collideWithObjects()
607 return m_prop
.collideWithObjects
;
610 void GenericCAO::initialize(const std::string
&data
)
612 infostream
<<"GenericCAO: Got init data"<<std::endl
;
613 std::istringstream
is(data
, std::ios::binary
);
614 int num_messages
= 0;
616 u8 version
= readU8(is
);
618 if(version
== 1) // In PROTOCOL_VERSION 14
620 m_name
= deSerializeString(is
);
621 m_is_player
= readU8(is
);
623 m_position
= readV3F1000(is
);
624 m_yaw
= readF1000(is
);
626 num_messages
= readU8(is
);
628 else if(version
== 0) // In PROTOCOL_VERSION 13
630 m_name
= deSerializeString(is
);
631 m_is_player
= readU8(is
);
632 m_position
= readV3F1000(is
);
633 m_yaw
= readF1000(is
);
635 num_messages
= readU8(is
);
639 errorstream
<<"GenericCAO: Unsupported init data version"
644 for(int i
=0; i
<num_messages
; i
++)
646 std::string message
= deSerializeLongString(is
);
647 processMessage(message
);
650 pos_translator
.init(m_position
);
655 Player
*player
= m_env
->getPlayer(m_name
.c_str());
656 if(player
&& player
->isLocal())
658 m_is_local_player
= true;
659 m_is_visible
= false;
660 LocalPlayer
* localplayer
= dynamic_cast<LocalPlayer
*>(player
);
662 assert( localplayer
!= NULL
);
663 localplayer
->setCAO(this);
665 m_env
->addPlayerName(m_name
.c_str());
669 GenericCAO::~GenericCAO()
673 m_env
->removePlayerName(m_name
.c_str());
675 removeFromScene(true);
678 core::aabbox3d
<f32
>* GenericCAO::getSelectionBox()
680 if(!m_prop
.is_visible
|| !m_is_visible
|| m_is_local_player
|| getParent() != NULL
)
682 return &m_selection_box
;
685 v3f
GenericCAO::getPosition()
687 if (getParent() != NULL
) {
688 scene::ISceneNode
*node
= getSceneNode();
690 return node
->getAbsolutePosition();
694 return pos_translator
.vect_show
;
697 scene::ISceneNode
* GenericCAO::getSceneNode()
701 if (m_animated_meshnode
)
702 return m_animated_meshnode
;
703 if (m_wield_meshnode
)
704 return m_wield_meshnode
;
710 scene::IMeshSceneNode
* GenericCAO::getMeshSceneNode()
715 scene::IAnimatedMeshSceneNode
* GenericCAO::getAnimatedMeshSceneNode()
717 return m_animated_meshnode
;
720 WieldMeshSceneNode
* GenericCAO::getWieldMeshSceneNode()
722 return m_wield_meshnode
;
725 scene::IBillboardSceneNode
* GenericCAO::getSpriteSceneNode()
730 void GenericCAO::setChildrenVisible(bool toset
)
732 for (std::vector
<u16
>::size_type i
= 0; i
< m_children
.size(); i
++) {
733 GenericCAO
*obj
= m_env
->getGenericCAO(m_children
[i
]);
735 obj
->setVisible(toset
);
740 void GenericCAO::setAttachments()
745 ClientActiveObject
* GenericCAO::getParent()
747 ClientActiveObject
*obj
= NULL
;
749 u16 attached_id
= m_env
->attachement_parent_ids
[getId()];
751 if ((attached_id
!= 0) &&
752 (attached_id
!= getId())) {
753 obj
= m_env
->getActiveObject(attached_id
);
758 void GenericCAO::removeFromScene(bool permanent
)
760 // Should be true when removing the object permanently and false when refreshing (eg: updating visuals)
761 if((m_env
!= NULL
) && (permanent
))
763 for (std::vector
<u16
>::size_type i
= 0; i
< m_children
.size(); i
++) {
764 u16 ci
= m_children
[i
];
765 if (m_env
->attachement_parent_ids
[ci
] == getId()) {
766 m_env
->attachement_parent_ids
[ci
] = 0;
770 m_env
->attachement_parent_ids
[getId()] = 0;
772 LocalPlayer
* player
= m_env
->getLocalPlayer();
773 if (this == player
->parent
) {
774 player
->parent
= NULL
;
775 player
->isAttached
= false;
781 m_meshnode
->remove();
785 if(m_animated_meshnode
)
787 m_animated_meshnode
->remove();
788 m_animated_meshnode
->drop();
789 m_animated_meshnode
= NULL
;
793 m_wield_meshnode
->remove();
794 m_wield_meshnode
->drop();
795 m_wield_meshnode
= NULL
;
799 m_spritenode
->remove();
800 m_spritenode
->drop();
805 m_textnode
->remove();
811 void GenericCAO::addToScene(scene::ISceneManager
*smgr
, ITextureSource
*tsrc
,
817 if (getSceneNode() != NULL
)
820 m_visuals_expired
= false;
822 if(!m_prop
.is_visible
)
825 //video::IVideoDriver* driver = smgr->getVideoDriver();
827 if(m_prop
.visual
== "sprite")
829 infostream
<<"GenericCAO::addToScene(): single_sprite"<<std::endl
;
830 m_spritenode
= smgr
->addBillboardSceneNode(
831 NULL
, v2f(1, 1), v3f(0,0,0), -1);
832 m_spritenode
->grab();
833 m_spritenode
->setMaterialTexture(0,
834 tsrc
->getTextureForMesh("unknown_node.png"));
835 m_spritenode
->setMaterialFlag(video::EMF_LIGHTING
, false);
836 m_spritenode
->setMaterialFlag(video::EMF_BILINEAR_FILTER
, false);
837 m_spritenode
->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF
);
838 m_spritenode
->setMaterialFlag(video::EMF_FOG_ENABLE
, true);
839 u8 li
= m_last_light
;
840 m_spritenode
->setColor(video::SColor(255,li
,li
,li
));
841 m_spritenode
->setSize(m_prop
.visual_size
*BS
);
843 const float txs
= 1.0 / 1;
844 const float tys
= 1.0 / 1;
845 setBillboardTextureMatrix(m_spritenode
,
849 else if(m_prop
.visual
== "upright_sprite") {
850 scene::SMesh
*mesh
= new scene::SMesh();
851 double dx
= BS
*m_prop
.visual_size
.X
/2;
852 double dy
= BS
*m_prop
.visual_size
.Y
/2;
854 scene::IMeshBuffer
*buf
= new scene::SMeshBuffer();
855 u8 li
= m_last_light
;
856 video::SColor
c(255,li
,li
,li
);
857 video::S3DVertex vertices
[4] =
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),
864 u16 indices
[] = {0,1,2,2,3,0};
865 buf
->append(vertices
, 4, indices
, 6);
867 buf
->getMaterial().setFlag(video::EMF_LIGHTING
, false);
868 buf
->getMaterial().setFlag(video::EMF_BILINEAR_FILTER
, false);
869 buf
->getMaterial().setFlag(video::EMF_FOG_ENABLE
, true);
870 buf
->getMaterial().MaterialType
= video::EMT_TRANSPARENT_ALPHA_CHANNEL
;
872 mesh
->addMeshBuffer(buf
);
876 scene::IMeshBuffer
*buf
= new scene::SMeshBuffer();
877 u8 li
= m_last_light
;
878 video::SColor
c(255,li
,li
,li
);
879 video::S3DVertex vertices
[4] =
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),
886 u16 indices
[] = {0,1,2,2,3,0};
887 buf
->append(vertices
, 4, indices
, 6);
889 buf
->getMaterial().setFlag(video::EMF_LIGHTING
, false);
890 buf
->getMaterial().setFlag(video::EMF_BILINEAR_FILTER
, false);
891 buf
->getMaterial().setFlag(video::EMF_FOG_ENABLE
, true);
892 buf
->getMaterial().MaterialType
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF
;
894 mesh
->addMeshBuffer(buf
);
897 m_meshnode
= smgr
->addMeshSceneNode(mesh
, NULL
);
900 // Set it to use the materials of the meshbuffers directly.
901 // This is needed for changing the texture in the future
902 m_meshnode
->setReadOnlyMaterials(true);
904 else if(m_prop
.visual
== "cube") {
905 infostream
<<"GenericCAO::addToScene(): cube"<<std::endl
;
906 scene::IMesh
*mesh
= createCubeMesh(v3f(BS
,BS
,BS
));
907 m_meshnode
= smgr
->addMeshSceneNode(mesh
, NULL
);
911 m_meshnode
->setScale(v3f(m_prop
.visual_size
.X
,
912 m_prop
.visual_size
.Y
,
913 m_prop
.visual_size
.X
));
914 u8 li
= m_last_light
;
915 setMeshColor(m_meshnode
->getMesh(), video::SColor(255,li
,li
,li
));
917 m_meshnode
->setMaterialFlag(video::EMF_LIGHTING
, false);
918 m_meshnode
->setMaterialFlag(video::EMF_BILINEAR_FILTER
, false);
919 m_meshnode
->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF
);
920 m_meshnode
->setMaterialFlag(video::EMF_FOG_ENABLE
, true);
922 else if(m_prop
.visual
== "mesh") {
923 infostream
<<"GenericCAO::addToScene(): mesh"<<std::endl
;
924 scene::IAnimatedMesh
*mesh
= m_gamedef
->getMesh(m_prop
.mesh
);
927 m_animated_meshnode
= smgr
->addAnimatedMeshSceneNode(mesh
, NULL
);
928 m_animated_meshnode
->grab();
929 mesh
->drop(); // The scene node took hold of it
930 m_animated_meshnode
->animateJoints(); // Needed for some animations
931 m_animated_meshnode
->setScale(v3f(m_prop
.visual_size
.X
,
932 m_prop
.visual_size
.Y
,
933 m_prop
.visual_size
.X
));
934 u8 li
= m_last_light
;
935 setMeshColor(m_animated_meshnode
->getMesh(), video::SColor(255,li
,li
,li
));
937 bool backface_culling
= m_prop
.backface_culling
;
939 backface_culling
= false;
941 m_animated_meshnode
->setMaterialFlag(video::EMF_LIGHTING
, false);
942 m_animated_meshnode
->setMaterialFlag(video::EMF_BILINEAR_FILTER
, false);
943 m_animated_meshnode
->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF
);
944 m_animated_meshnode
->setMaterialFlag(video::EMF_FOG_ENABLE
, true);
945 m_animated_meshnode
->setMaterialFlag(video::EMF_BACK_FACE_CULLING
, backface_culling
);
948 errorstream
<<"GenericCAO::addToScene(): Could not load mesh "<<m_prop
.mesh
<<std::endl
;
950 else if(m_prop
.visual
== "wielditem") {
951 infostream
<<"GenericCAO::addToScene(): wielditem"<<std::endl
;
952 infostream
<<"textures: "<<m_prop
.textures
.size()<<std::endl
;
953 if(m_prop
.textures
.size() >= 1){
954 infostream
<<"textures[0]: "<<m_prop
.textures
[0]<<std::endl
;
955 IItemDefManager
*idef
= m_gamedef
->idef();
956 ItemStack
item(m_prop
.textures
[0], 1, 0, "", idef
);
958 m_wield_meshnode
= new WieldMeshSceneNode(
959 smgr
->getRootSceneNode(), smgr
, -1);
960 m_wield_meshnode
->setItem(item
, m_gamedef
);
962 m_wield_meshnode
->setScale(v3f(m_prop
.visual_size
.X
/2,
963 m_prop
.visual_size
.Y
/2,
964 m_prop
.visual_size
.X
/2));
965 u8 li
= m_last_light
;
966 m_wield_meshnode
->setColor(video::SColor(255,li
,li
,li
));
969 infostream
<<"GenericCAO::addToScene(): \""<<m_prop
.visual
970 <<"\" not supported"<<std::endl
;
974 scene::ISceneNode
*node
= getSceneNode();
975 if (node
&& m_is_player
&& !m_is_local_player
) {
976 // Add a text node for showing the name
977 gui::IGUIEnvironment
* gui
= irr
->getGUIEnvironment();
978 std::wstring wname
= utf8_to_wide(m_name
);
979 m_textnode
= smgr
->addTextSceneNode(gui
->getSkin()->getFont(),
980 wname
.c_str(), m_nametag_color
, node
);
982 m_textnode
->setPosition(v3f(0, BS
*1.1, 0));
984 // Enforce hiding nametag,
985 // because if freetype is enabled, a grey
986 // shadow can remain.
987 m_textnode
->setVisible(m_nametag_color
.getAlpha() > 0);
992 updateBonePosition();
996 void GenericCAO::updateLight(u8 light_at_pos
)
998 // Don't update light of attached one
999 if (getParent() != NULL
) {
1003 updateLightNoCheck(light_at_pos
);
1005 // Update light of all children
1006 for (std::vector
<u16
>::size_type i
= 0; i
< m_children
.size(); i
++) {
1007 ClientActiveObject
*obj
= m_env
->getActiveObject(m_children
[i
]);
1009 obj
->updateLightNoCheck(light_at_pos
);
1014 void GenericCAO::updateLightNoCheck(u8 light_at_pos
)
1016 u8 li
= decode_light(light_at_pos
);
1017 if (li
!= m_last_light
) {
1019 video::SColor
color(255,li
,li
,li
);
1021 setMeshColor(m_meshnode
->getMesh(), color
);
1022 } else if (m_animated_meshnode
) {
1023 setMeshColor(m_animated_meshnode
->getMesh(), color
);
1024 } else if (m_wield_meshnode
) {
1025 m_wield_meshnode
->setColor(color
);
1026 } else if (m_spritenode
) {
1027 m_spritenode
->setColor(color
);
1032 v3s16
GenericCAO::getLightPosition()
1034 return floatToInt(m_position
, BS
);
1037 void GenericCAO::updateNodePos()
1039 if (getParent() != NULL
)
1042 scene::ISceneNode
*node
= getSceneNode();
1045 v3s16 camera_offset
= m_env
->getCameraOffset();
1046 node
->setPosition(pos_translator
.vect_show
- intToFloat(camera_offset
, BS
));
1047 if (node
!= m_spritenode
) { // rotate if not a sprite
1048 v3f rot
= node
->getRotation();
1050 node
->setRotation(rot
);
1055 void GenericCAO::step(float dtime
, ClientEnvironment
*env
)
1057 // Handel model of local player instantly to prevent lags
1058 if(m_is_local_player
)
1060 LocalPlayer
*player
= m_env
->getLocalPlayer();
1064 int old_anim
= player
->last_animation
;
1065 float old_anim_speed
= player
->last_animation_speed
;
1066 m_position
= player
->getPosition() + v3f(0,BS
,0);
1067 m_velocity
= v3f(0,0,0);
1068 m_acceleration
= v3f(0,0,0);
1069 pos_translator
.vect_show
= m_position
;
1070 m_yaw
= player
->getYaw();
1071 PlayerControl controls
= player
->getPlayerControl();
1073 bool walking
= false;
1074 if(controls
.up
|| controls
.down
|| controls
.left
|| controls
.right
)
1077 f32 new_speed
= player
->local_animation_speed
;
1078 v2s32 new_anim
= v2s32(0,0);
1079 bool allow_update
= false;
1081 // increase speed if using fast or flying fast
1082 if((g_settings
->getBool("fast_move") &&
1083 m_gamedef
->checkLocalPrivilege("fast")) &&
1085 (!player
->touching_ground
&&
1086 g_settings
->getBool("free_move") &&
1087 m_gamedef
->checkLocalPrivilege("fly"))))
1089 // slowdown speed if sneeking
1090 if(controls
.sneak
&& walking
)
1093 if(walking
&& (controls
.LMB
|| controls
.RMB
))
1095 new_anim
= player
->local_animations
[3];
1096 player
->last_animation
= WD_ANIM
;
1097 } else if(walking
) {
1098 new_anim
= player
->local_animations
[1];
1099 player
->last_animation
= WALK_ANIM
;
1100 } else if(controls
.LMB
|| controls
.RMB
) {
1101 new_anim
= player
->local_animations
[2];
1102 player
->last_animation
= DIG_ANIM
;
1105 // Apply animations if input detected and not attached
1106 // or set idle animation
1107 if ((new_anim
.X
+ new_anim
.Y
) > 0 && !player
->isAttached
)
1109 allow_update
= true;
1110 m_animation_range
= new_anim
;
1111 m_animation_speed
= new_speed
;
1112 player
->last_animation_speed
= m_animation_speed
;
1114 player
->last_animation
= NO_ANIM
;
1116 if (old_anim
!= NO_ANIM
)
1118 m_animation_range
= player
->local_animations
[0];
1123 // Update local player animations
1124 if ((player
->last_animation
!= old_anim
||
1125 m_animation_speed
!= old_anim_speed
) &&
1126 player
->last_animation
!= NO_ANIM
&& allow_update
)
1132 if(m_visuals_expired
&& m_smgr
&& m_irr
){
1133 m_visuals_expired
= false;
1135 // Attachments, part 1: All attached objects must be unparented first,
1136 // or Irrlicht causes a segmentation fault
1137 for(std::vector
<u16
>::iterator ci
= m_children
.begin();
1138 ci
!= m_children
.end();)
1140 if (m_env
->attachement_parent_ids
[*ci
] != getId()) {
1141 ci
= m_children
.erase(ci
);
1144 ClientActiveObject
*obj
= m_env
->getActiveObject(*ci
);
1146 scene::ISceneNode
*child_node
= obj
->getSceneNode();
1148 child_node
->setParent(m_smgr
->getRootSceneNode());
1153 removeFromScene(false);
1154 addToScene(m_smgr
, m_gamedef
->tsrc(), m_irr
);
1156 // Attachments, part 2: Now that the parent has been refreshed, put its attachments back
1157 for (std::vector
<u16
>::size_type i
= 0; i
< m_children
.size(); i
++) {
1158 // Get the object of the child
1159 ClientActiveObject
*obj
= m_env
->getActiveObject(m_children
[i
]);
1161 obj
->setAttachments();
1165 // Make sure m_is_visible is always applied
1166 scene::ISceneNode
*node
= getSceneNode();
1168 node
->setVisible(m_is_visible
);
1170 if(getParent() != NULL
) // Attachments should be glued to their parent by Irrlicht
1172 // Set these for later
1173 m_position
= getPosition();
1174 m_velocity
= v3f(0,0,0);
1175 m_acceleration
= v3f(0,0,0);
1176 pos_translator
.vect_show
= m_position
;
1178 if(m_is_local_player
) // Update local player attachment position
1180 LocalPlayer
*player
= m_env
->getLocalPlayer();
1181 player
->overridePosition
= getParent()->getPosition();
1182 m_env
->getLocalPlayer()->parent
= getParent();
1185 v3f lastpos
= pos_translator
.vect_show
;
1189 core::aabbox3d
<f32
> box
= m_prop
.collisionbox
;
1192 collisionMoveResult moveresult
;
1193 f32 pos_max_d
= BS
*0.125; // Distance per iteration
1194 v3f p_pos
= m_position
;
1195 v3f p_velocity
= m_velocity
;
1196 v3f p_acceleration
= m_acceleration
;
1197 moveresult
= collisionMoveSimple(env
,env
->getGameDef(),
1198 pos_max_d
, box
, m_prop
.stepheight
, dtime
,
1199 p_pos
, p_velocity
, p_acceleration
,
1200 this, m_prop
.collideWithObjects
);
1203 m_velocity
= p_velocity
;
1204 m_acceleration
= p_acceleration
;
1206 bool is_end_position
= moveresult
.collides
;
1207 pos_translator
.update(m_position
, is_end_position
, dtime
);
1208 pos_translator
.translate(dtime
);
1211 m_position
+= dtime
* m_velocity
+ 0.5 * dtime
* dtime
* m_acceleration
;
1212 m_velocity
+= dtime
* m_acceleration
;
1213 pos_translator
.update(m_position
, pos_translator
.aim_is_end
,
1214 pos_translator
.anim_time
);
1215 pos_translator
.translate(dtime
);
1219 float moved
= lastpos
.getDistanceFrom(pos_translator
.vect_show
);
1220 m_step_distance_counter
+= moved
;
1221 if(m_step_distance_counter
> 1.5*BS
)
1223 m_step_distance_counter
= 0;
1224 if(!m_is_local_player
&& m_prop
.makes_footstep_sound
)
1226 INodeDefManager
*ndef
= m_gamedef
->ndef();
1227 v3s16 p
= floatToInt(getPosition() + v3f(0,
1228 (m_prop
.collisionbox
.MinEdge
.Y
-0.5)*BS
, 0), BS
);
1229 MapNode n
= m_env
->getMap().getNodeNoEx(p
);
1230 SimpleSoundSpec spec
= ndef
->get(n
).sound_footstep
;
1231 m_gamedef
->sound()->playSoundAt(spec
, false, getPosition());
1236 m_anim_timer
+= dtime
;
1237 if(m_anim_timer
>= m_anim_framelength
)
1239 m_anim_timer
-= m_anim_framelength
;
1241 if(m_anim_frame
>= m_anim_num_frames
)
1247 if(m_reset_textures_timer
>= 0)
1249 m_reset_textures_timer
-= dtime
;
1250 if(m_reset_textures_timer
<= 0){
1251 m_reset_textures_timer
= -1;
1255 if(getParent() == NULL
&& fabs(m_prop
.automatic_rotate
) > 0.001)
1257 m_yaw
+= dtime
* m_prop
.automatic_rotate
* 180 / M_PI
;
1261 if (getParent() == NULL
&& m_prop
.automatic_face_movement_dir
&&
1262 (fabs(m_velocity
.Z
) > 0.001 || fabs(m_velocity
.X
) > 0.001))
1264 m_yaw
= atan2(m_velocity
.Z
,m_velocity
.X
) * 180 / M_PI
1265 + m_prop
.automatic_face_movement_dir_offset
;
1270 void GenericCAO::updateTexturePos()
1274 scene::ICameraSceneNode
* camera
=
1275 m_spritenode
->getSceneManager()->getActiveCamera();
1278 v3f cam_to_entity
= m_spritenode
->getAbsolutePosition()
1279 - camera
->getAbsolutePosition();
1280 cam_to_entity
.normalize();
1282 int row
= m_tx_basepos
.Y
;
1283 int col
= m_tx_basepos
.X
;
1285 if(m_tx_select_horiz_by_yawpitch
)
1287 if(cam_to_entity
.Y
> 0.75)
1289 else if(cam_to_entity
.Y
< -0.75)
1293 atan2(cam_to_entity
.Z
, cam_to_entity
.X
) / M_PI
* 180.;
1294 float dir
= mob_dir
- m_yaw
;
1295 dir
= wrapDegrees_180(dir
);
1296 //infostream<<"id="<<m_id<<" dir="<<dir<<std::endl;
1297 if(fabs(wrapDegrees_180(dir
- 0)) <= 45.1)
1299 else if(fabs(wrapDegrees_180(dir
- 90)) <= 45.1)
1301 else if(fabs(wrapDegrees_180(dir
- 180)) <= 45.1)
1303 else if(fabs(wrapDegrees_180(dir
+ 90)) <= 45.1)
1310 // Animation goes downwards
1311 row
+= m_anim_frame
;
1313 float txs
= m_tx_size
.X
;
1314 float tys
= m_tx_size
.Y
;
1315 setBillboardTextureMatrix(m_spritenode
,
1316 txs
, tys
, col
, row
);
1320 void GenericCAO::updateTextures(const std::string
&mod
)
1322 ITextureSource
*tsrc
= m_gamedef
->tsrc();
1324 bool use_trilinear_filter
= g_settings
->getBool("trilinear_filter");
1325 bool use_bilinear_filter
= g_settings
->getBool("bilinear_filter");
1326 bool use_anisotropic_filter
= g_settings
->getBool("anisotropic_filter");
1330 if(m_prop
.visual
== "sprite")
1332 std::string texturestring
= "unknown_node.png";
1333 if(m_prop
.textures
.size() >= 1)
1334 texturestring
= m_prop
.textures
[0];
1335 texturestring
+= mod
;
1336 m_spritenode
->setMaterialTexture(0,
1337 tsrc
->getTextureForMesh(texturestring
));
1339 // This allows setting per-material colors. However, until a real lighting
1340 // system is added, the code below will have no effect. Once MineTest
1341 // has directional lighting, it should work automatically.
1342 if(m_prop
.colors
.size() >= 1)
1344 m_spritenode
->getMaterial(0).AmbientColor
= m_prop
.colors
[0];
1345 m_spritenode
->getMaterial(0).DiffuseColor
= m_prop
.colors
[0];
1346 m_spritenode
->getMaterial(0).SpecularColor
= m_prop
.colors
[0];
1349 m_spritenode
->getMaterial(0).setFlag(video::EMF_TRILINEAR_FILTER
, use_trilinear_filter
);
1350 m_spritenode
->getMaterial(0).setFlag(video::EMF_BILINEAR_FILTER
, use_bilinear_filter
);
1351 m_spritenode
->getMaterial(0).setFlag(video::EMF_ANISOTROPIC_FILTER
, use_anisotropic_filter
);
1354 if(m_animated_meshnode
)
1356 if(m_prop
.visual
== "mesh")
1358 for (u32 i
= 0; i
< m_prop
.textures
.size() &&
1359 i
< m_animated_meshnode
->getMaterialCount(); ++i
)
1361 std::string texturestring
= m_prop
.textures
[i
];
1362 if(texturestring
== "")
1363 continue; // Empty texture string means don't modify that material
1364 texturestring
+= mod
;
1365 video::ITexture
* texture
= tsrc
->getTextureForMesh(texturestring
);
1368 errorstream
<<"GenericCAO::updateTextures(): Could not load texture "<<texturestring
<<std::endl
;
1372 // Set material flags and texture
1373 video::SMaterial
& material
= m_animated_meshnode
->getMaterial(i
);
1374 material
.TextureLayer
[0].Texture
= texture
;
1375 material
.setFlag(video::EMF_LIGHTING
, false);
1376 material
.setFlag(video::EMF_BILINEAR_FILTER
, false);
1378 m_animated_meshnode
->getMaterial(i
)
1379 .setFlag(video::EMF_TRILINEAR_FILTER
, use_trilinear_filter
);
1380 m_animated_meshnode
->getMaterial(i
)
1381 .setFlag(video::EMF_BILINEAR_FILTER
, use_bilinear_filter
);
1382 m_animated_meshnode
->getMaterial(i
)
1383 .setFlag(video::EMF_ANISOTROPIC_FILTER
, use_anisotropic_filter
);
1385 for (u32 i
= 0; i
< m_prop
.colors
.size() &&
1386 i
< m_animated_meshnode
->getMaterialCount(); ++i
)
1388 // This allows setting per-material colors. However, until a real lighting
1389 // system is added, the code below will have no effect. Once MineTest
1390 // has directional lighting, it should work automatically.
1391 m_animated_meshnode
->getMaterial(i
).AmbientColor
= m_prop
.colors
[i
];
1392 m_animated_meshnode
->getMaterial(i
).DiffuseColor
= m_prop
.colors
[i
];
1393 m_animated_meshnode
->getMaterial(i
).SpecularColor
= m_prop
.colors
[i
];
1399 if(m_prop
.visual
== "cube")
1401 for (u32 i
= 0; i
< 6; ++i
)
1403 std::string texturestring
= "unknown_node.png";
1404 if(m_prop
.textures
.size() > i
)
1405 texturestring
= m_prop
.textures
[i
];
1406 texturestring
+= mod
;
1409 // Set material flags and texture
1410 video::SMaterial
& material
= m_meshnode
->getMaterial(i
);
1411 material
.setFlag(video::EMF_LIGHTING
, false);
1412 material
.setFlag(video::EMF_BILINEAR_FILTER
, false);
1413 material
.setTexture(0,
1414 tsrc
->getTextureForMesh(texturestring
));
1415 material
.getTextureMatrix(0).makeIdentity();
1417 // This allows setting per-material colors. However, until a real lighting
1418 // system is added, the code below will have no effect. Once MineTest
1419 // has directional lighting, it should work automatically.
1420 if(m_prop
.colors
.size() > i
)
1422 m_meshnode
->getMaterial(i
).AmbientColor
= m_prop
.colors
[i
];
1423 m_meshnode
->getMaterial(i
).DiffuseColor
= m_prop
.colors
[i
];
1424 m_meshnode
->getMaterial(i
).SpecularColor
= m_prop
.colors
[i
];
1427 m_meshnode
->getMaterial(i
).setFlag(video::EMF_TRILINEAR_FILTER
, use_trilinear_filter
);
1428 m_meshnode
->getMaterial(i
).setFlag(video::EMF_BILINEAR_FILTER
, use_bilinear_filter
);
1429 m_meshnode
->getMaterial(i
).setFlag(video::EMF_ANISOTROPIC_FILTER
, use_anisotropic_filter
);
1432 else if(m_prop
.visual
== "upright_sprite")
1434 scene::IMesh
*mesh
= m_meshnode
->getMesh();
1436 std::string tname
= "unknown_object.png";
1437 if(m_prop
.textures
.size() >= 1)
1438 tname
= m_prop
.textures
[0];
1440 scene::IMeshBuffer
*buf
= mesh
->getMeshBuffer(0);
1441 buf
->getMaterial().setTexture(0,
1442 tsrc
->getTextureForMesh(tname
));
1444 // This allows setting per-material colors. However, until a real lighting
1445 // system is added, the code below will have no effect. Once MineTest
1446 // has directional lighting, it should work automatically.
1447 if(m_prop
.colors
.size() >= 1)
1449 buf
->getMaterial().AmbientColor
= m_prop
.colors
[0];
1450 buf
->getMaterial().DiffuseColor
= m_prop
.colors
[0];
1451 buf
->getMaterial().SpecularColor
= m_prop
.colors
[0];
1454 buf
->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER
, use_trilinear_filter
);
1455 buf
->getMaterial().setFlag(video::EMF_BILINEAR_FILTER
, use_bilinear_filter
);
1456 buf
->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER
, use_anisotropic_filter
);
1459 std::string tname
= "unknown_object.png";
1460 if(m_prop
.textures
.size() >= 2)
1461 tname
= m_prop
.textures
[1];
1462 else if(m_prop
.textures
.size() >= 1)
1463 tname
= m_prop
.textures
[0];
1465 scene::IMeshBuffer
*buf
= mesh
->getMeshBuffer(1);
1466 buf
->getMaterial().setTexture(0,
1467 tsrc
->getTextureForMesh(tname
));
1469 // This allows setting per-material colors. However, until a real lighting
1470 // system is added, the code below will have no effect. Once MineTest
1471 // has directional lighting, it should work automatically.
1472 if(m_prop
.colors
.size() >= 2)
1474 buf
->getMaterial().AmbientColor
= m_prop
.colors
[1];
1475 buf
->getMaterial().DiffuseColor
= m_prop
.colors
[1];
1476 buf
->getMaterial().SpecularColor
= m_prop
.colors
[1];
1478 else if(m_prop
.colors
.size() >= 1)
1480 buf
->getMaterial().AmbientColor
= m_prop
.colors
[0];
1481 buf
->getMaterial().DiffuseColor
= m_prop
.colors
[0];
1482 buf
->getMaterial().SpecularColor
= m_prop
.colors
[0];
1485 buf
->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER
, use_trilinear_filter
);
1486 buf
->getMaterial().setFlag(video::EMF_BILINEAR_FILTER
, use_bilinear_filter
);
1487 buf
->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER
, use_anisotropic_filter
);
1493 void GenericCAO::updateAnimation()
1495 if(m_animated_meshnode
== NULL
)
1498 if (m_animated_meshnode
->getStartFrame() != m_animation_range
.X
||
1499 m_animated_meshnode
->getEndFrame() != m_animation_range
.Y
)
1500 m_animated_meshnode
->setFrameLoop(m_animation_range
.X
, m_animation_range
.Y
);
1501 if (m_animated_meshnode
->getAnimationSpeed() != m_animation_speed
)
1502 m_animated_meshnode
->setAnimationSpeed(m_animation_speed
);
1503 m_animated_meshnode
->setTransitionTime(m_animation_blend
);
1504 // Requires Irrlicht 1.8 or greater
1505 #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR > 1
1506 if (m_animated_meshnode
->getLoopMode() != m_animation_loop
)
1507 m_animated_meshnode
->setLoopMode(m_animation_loop
);
1511 void GenericCAO::updateBonePosition()
1513 if(m_bone_position
.empty() || m_animated_meshnode
== NULL
)
1516 m_animated_meshnode
->setJointMode(irr::scene::EJUOR_CONTROL
); // To write positions to the mesh on render
1517 for(std::map
<std::string
,
1518 core::vector2d
<v3f
> >::const_iterator ii
= m_bone_position
.begin();
1519 ii
!= m_bone_position
.end(); ++ii
)
1521 std::string bone_name
= (*ii
).first
;
1522 v3f bone_pos
= (*ii
).second
.X
;
1523 v3f bone_rot
= (*ii
).second
.Y
;
1524 irr::scene::IBoneSceneNode
* bone
= m_animated_meshnode
->getJointNode(bone_name
.c_str());
1527 bone
->setPosition(bone_pos
);
1528 bone
->setRotation(bone_rot
);
1533 void GenericCAO::updateAttachments()
1536 if (getParent() == NULL
) { // Detach or don't attach
1537 scene::ISceneNode
*node
= getSceneNode();
1539 v3f old_position
= node
->getAbsolutePosition();
1540 v3f old_rotation
= node
->getRotation();
1541 node
->setParent(m_smgr
->getRootSceneNode());
1542 node
->setPosition(old_position
);
1543 node
->setRotation(old_rotation
);
1544 node
->updateAbsolutePosition();
1546 if (m_is_local_player
) {
1547 LocalPlayer
*player
= m_env
->getLocalPlayer();
1548 player
->isAttached
= false;
1553 scene::ISceneNode
*my_node
= getSceneNode();
1555 scene::ISceneNode
*parent_node
= getParent()->getSceneNode();
1556 scene::IAnimatedMeshSceneNode
*parent_animated_mesh_node
=
1557 getParent()->getAnimatedMeshSceneNode();
1558 if (parent_animated_mesh_node
&& m_attachment_bone
!= "") {
1559 parent_node
= parent_animated_mesh_node
->getJointNode(m_attachment_bone
.c_str());
1562 if (my_node
&& parent_node
) {
1563 my_node
->setParent(parent_node
);
1564 my_node
->setPosition(m_attachment_position
);
1565 my_node
->setRotation(m_attachment_rotation
);
1566 my_node
->updateAbsolutePosition();
1568 if (m_is_local_player
) {
1569 LocalPlayer
*player
= m_env
->getLocalPlayer();
1570 player
->isAttached
= true;
1575 void GenericCAO::processMessage(const std::string
&data
)
1577 //infostream<<"GenericCAO: Got message"<<std::endl;
1578 std::istringstream
is(data
, std::ios::binary
);
1580 u8 cmd
= readU8(is
);
1581 if(cmd
== GENERIC_CMD_SET_PROPERTIES
)
1583 m_prop
= gob_read_set_properties(is
);
1585 m_selection_box
= m_prop
.collisionbox
;
1586 m_selection_box
.MinEdge
*= BS
;
1587 m_selection_box
.MaxEdge
*= BS
;
1589 m_tx_size
.X
= 1.0 / m_prop
.spritediv
.X
;
1590 m_tx_size
.Y
= 1.0 / m_prop
.spritediv
.Y
;
1592 if(!m_initial_tx_basepos_set
){
1593 m_initial_tx_basepos_set
= true;
1594 m_tx_basepos
= m_prop
.initial_sprite_basepos
;
1599 else if(cmd
== GENERIC_CMD_UPDATE_POSITION
)
1601 // Not sent by the server if this object is an attachment.
1602 // We might however get here if the server notices the object being detached before the client.
1603 m_position
= readV3F1000(is
);
1604 m_velocity
= readV3F1000(is
);
1605 m_acceleration
= readV3F1000(is
);
1606 if(fabs(m_prop
.automatic_rotate
) < 0.001)
1607 m_yaw
= readF1000(is
);
1610 bool do_interpolate
= readU8(is
);
1611 bool is_end_position
= readU8(is
);
1612 float update_interval
= readF1000(is
);
1614 // Place us a bit higher if we're physical, to not sink into
1615 // the ground due to sucky collision detection...
1617 m_position
+= v3f(0,0.002,0);
1619 if(getParent() != NULL
) // Just in case
1624 if(!m_prop
.physical
)
1625 pos_translator
.update(m_position
, is_end_position
, update_interval
);
1627 pos_translator
.init(m_position
);
1631 else if(cmd
== GENERIC_CMD_SET_TEXTURE_MOD
) {
1632 std::string mod
= deSerializeString(is
);
1633 updateTextures(mod
);
1635 else if(cmd
== GENERIC_CMD_SET_SPRITE
) {
1636 v2s16 p
= readV2S16(is
);
1637 int num_frames
= readU16(is
);
1638 float framelength
= readF1000(is
);
1639 bool select_horiz_by_yawpitch
= readU8(is
);
1642 m_anim_num_frames
= num_frames
;
1643 m_anim_framelength
= framelength
;
1644 m_tx_select_horiz_by_yawpitch
= select_horiz_by_yawpitch
;
1648 else if(cmd
== GENERIC_CMD_SET_PHYSICS_OVERRIDE
) {
1649 float override_speed
= readF1000(is
);
1650 float override_jump
= readF1000(is
);
1651 float override_gravity
= readF1000(is
);
1652 // these are sent inverted so we get true when the server sends nothing
1653 bool sneak
= !readU8(is
);
1654 bool sneak_glitch
= !readU8(is
);
1657 if(m_is_local_player
)
1659 LocalPlayer
*player
= m_env
->getLocalPlayer();
1660 player
->physics_override_speed
= override_speed
;
1661 player
->physics_override_jump
= override_jump
;
1662 player
->physics_override_gravity
= override_gravity
;
1663 player
->physics_override_sneak
= sneak
;
1664 player
->physics_override_sneak_glitch
= sneak_glitch
;
1667 else if(cmd
== GENERIC_CMD_SET_ANIMATION
) {
1668 // TODO: change frames send as v2s32 value
1669 v2f range
= readV2F1000(is
);
1670 if (!m_is_local_player
) {
1671 m_animation_range
= v2s32((s32
)range
.X
, (s32
)range
.Y
);
1672 m_animation_speed
= readF1000(is
);
1673 m_animation_blend
= readF1000(is
);
1674 // these are sent inverted so we get true when the server sends nothing
1675 m_animation_loop
= !readU8(is
);
1678 LocalPlayer
*player
= m_env
->getLocalPlayer();
1679 if(player
->last_animation
== NO_ANIM
)
1681 m_animation_range
= v2s32((s32
)range
.X
, (s32
)range
.Y
);
1682 m_animation_speed
= readF1000(is
);
1683 m_animation_blend
= readF1000(is
);
1684 // these are sent inverted so we get true when the server sends nothing
1685 m_animation_loop
= !readU8(is
);
1687 // update animation only if local animations present
1688 // and received animation is unknown (except idle animation)
1689 bool is_known
= false;
1690 for (int i
= 1;i
<4;i
++)
1692 if(m_animation_range
.Y
== player
->local_animations
[i
].Y
)
1696 (player
->local_animations
[1].Y
+ player
->local_animations
[2].Y
< 1))
1702 else if(cmd
== GENERIC_CMD_SET_BONE_POSITION
) {
1703 std::string bone
= deSerializeString(is
);
1704 v3f position
= readV3F1000(is
);
1705 v3f rotation
= readV3F1000(is
);
1706 m_bone_position
[bone
] = core::vector2d
<v3f
>(position
, rotation
);
1708 updateBonePosition();
1709 } else if (cmd
== GENERIC_CMD_ATTACH_TO
) {
1710 u16 parentID
= readS16(is
);
1711 u16 oldparent
= m_env
->attachement_parent_ids
[getId()];
1713 m_children
.erase(std::remove(m_children
.begin(), m_children
.end(),
1714 getId()), m_children
.end());
1716 m_env
->attachement_parent_ids
[getId()] = parentID
;
1717 GenericCAO
*parentobj
= m_env
->getGenericCAO(parentID
);
1720 parentobj
->m_children
.push_back(getId());
1723 m_attachment_bone
= deSerializeString(is
);
1724 m_attachment_position
= readV3F1000(is
);
1725 m_attachment_rotation
= readV3F1000(is
);
1727 // localplayer itself can't be attached to localplayer
1728 if (!m_is_local_player
) {
1729 m_attached_to_local
= getParent() != NULL
&& getParent()->isLocalPlayer();
1730 // Objects attached to the local player should be hidden by default
1731 m_is_visible
= !m_attached_to_local
;
1734 updateAttachments();
1736 else if(cmd
== GENERIC_CMD_PUNCHED
) {
1737 /*s16 damage =*/ readS16(is
);
1738 s16 result_hp
= readS16(is
);
1740 // Use this instead of the send damage to not interfere with prediction
1741 s16 damage
= m_hp
- result_hp
;
1749 // TODO: Execute defined fast response
1750 // As there is no definition, make a smoke puff
1751 ClientSimpleObject
*simple
= createSmokePuff(
1752 m_smgr
, m_env
, m_position
,
1753 m_prop
.visual_size
* BS
);
1754 m_env
->addSimpleObject(simple
);
1756 // TODO: Execute defined fast response
1757 // Flashing shall suffice as there is no definition
1758 m_reset_textures_timer
= 0.05;
1760 m_reset_textures_timer
+= 0.05 * damage
;
1761 updateTextures("^[brighten");
1765 else if(cmd
== GENERIC_CMD_UPDATE_ARMOR_GROUPS
) {
1766 m_armor_groups
.clear();
1767 int armor_groups_size
= readU16(is
);
1768 for(int i
=0; i
<armor_groups_size
; i
++)
1770 std::string name
= deSerializeString(is
);
1771 int rating
= readS16(is
);
1772 m_armor_groups
[name
] = rating
;
1774 } else if (cmd
== GENERIC_CMD_UPDATE_NAMETAG_ATTRIBUTES
) {
1775 readU8(is
); // version
1776 m_nametag_color
= readARGB8(is
);
1777 if (m_textnode
!= NULL
) {
1778 m_textnode
->setTextColor(m_nametag_color
);
1780 // Enforce hiding nametag,
1781 // because if freetype is enabled, a grey
1782 // shadow can remain.
1783 m_textnode
->setVisible(m_nametag_color
.getAlpha() > 0);
1788 /* \pre punchitem != NULL
1790 bool GenericCAO::directReportPunch(v3f dir
, const ItemStack
*punchitem
,
1791 float time_from_last_punch
)
1793 assert(punchitem
); // pre-condition
1794 const ToolCapabilities
*toolcap
=
1795 &punchitem
->getToolCapabilities(m_gamedef
->idef());
1796 PunchDamageResult result
= getPunchDamage(
1800 time_from_last_punch
);
1802 if(result
.did_punch
&& result
.damage
!= 0)
1804 if(result
.damage
< m_hp
)
1806 m_hp
-= result
.damage
;
1809 // TODO: Execute defined fast response
1810 // As there is no definition, make a smoke puff
1811 ClientSimpleObject
*simple
= createSmokePuff(
1812 m_smgr
, m_env
, m_position
,
1813 m_prop
.visual_size
* BS
);
1814 m_env
->addSimpleObject(simple
);
1816 // TODO: Execute defined fast response
1817 // Flashing shall suffice as there is no definition
1818 m_reset_textures_timer
= 0.05;
1819 if(result
.damage
>= 2)
1820 m_reset_textures_timer
+= 0.05 * result
.damage
;
1821 updateTextures("^[brighten");
1827 std::string
GenericCAO::debugInfoText()
1829 std::ostringstream
os(std::ios::binary
);
1830 os
<<"GenericCAO hp="<<m_hp
<<"\n";
1832 for(ItemGroupList::const_iterator i
= m_armor_groups
.begin();
1833 i
!= m_armor_groups
.end(); ++i
)
1835 os
<<i
->first
<<"="<<i
->second
<<", ";
1842 GenericCAO
proto_GenericCAO(NULL
, NULL
);