X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fcontent_cao.cpp;h=640ab6c7302ae9162785299c5936a553297356d7;hb=0a903e69fbd9b19d8d8da0593f31dec5807af566;hp=fc1df377a7875624a56156ca2df98741f78b5f34;hpb=601d1936c9ab4787d43f55d67900ed7c46fd3452;p=minetest.git diff --git a/src/content_cao.cpp b/src/content_cao.cpp index fc1df377a..640ab6c73 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -1,18 +1,18 @@ /* -Minetest-c55 -Copyright (C) 2010-2011 celeron55, Perttu Ahola +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Lesser General Public License for more details. -You should have received a copy of the GNU General Public License along +You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ @@ -30,16 +30,27 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "clientobject.h" #include "content_object.h" #include "mesh.h" -#include "utility.h" // For IntervalLimiter #include "itemdef.h" #include "tool.h" #include "content_cso.h" #include "sound.h" #include "nodedef.h" +#include "localplayer.h" +#include "util/numeric.h" // For IntervalLimiter +#include "util/serialize.h" +#include "util/mathconstants.h" +#include "map.h" +#include "main.h" // g_settings +#include +#include +#include + class Settings; struct ToolCapabilities; -core::map ClientActiveObject::m_types; +#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" + +std::map ClientActiveObject::m_types; /* SmoothTranslator @@ -163,6 +174,7 @@ class TestCAO : public ClientActiveObject void processMessage(const std::string &data); + bool getCollisionBox(aabb3f *toset) { return false; } private: scene::IMeshSceneNode *m_node; v3f m_position; @@ -211,7 +223,7 @@ void TestCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, // Set material buf->getMaterial().setFlag(video::EMF_LIGHTING, false); buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false); - buf->getMaterial().setTexture(0, tsrc->getTextureRaw("rat.png")); + buf->getMaterial().setTexture(0, tsrc->getTexture("rat.png")); buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true); buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; @@ -318,6 +330,7 @@ class ItemCAO : public ClientActiveObject std::string infoText() {return m_infotext;} + bool getCollisionBox(aabb3f *toset) { return false; } private: core::aabbox3d m_selection_box; scene::IMeshSceneNode *m_node; @@ -380,7 +393,7 @@ void ItemCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, buf->getMaterial().setFlag(video::EMF_LIGHTING, false); buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false); // Initialize with a generated placeholder texture - buf->getMaterial().setTexture(0, tsrc->getTextureRaw("")); + buf->getMaterial().setTexture(0, tsrc->getTexture("")); buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true); buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; @@ -461,7 +474,7 @@ void ItemCAO::updateTexture() IItemDefManager *idef = m_gamedef->idef(); ItemStack item; item.deSerialize(is, idef); - texture = item.getDefinition(idef).inventory_texture; + texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_gamedef); } catch(SerializationError &e) { @@ -533,191 +546,504 @@ void ItemCAO::initialize(const std::string &data) } /* - LuaEntityCAO + GenericCAO */ -#include "luaentity_common.h" +#include "genericobject.h" -class LuaEntityCAO : public ClientActiveObject +class GenericCAO : public ClientActiveObject { private: + // Only set at initialization + std::string m_name; + bool m_is_player; + bool m_is_local_player; + int m_id; + // Property-ish things + ObjectProperties m_prop; + // scene::ISceneManager *m_smgr; + IrrlichtDevice *m_irr; core::aabbox3d m_selection_box; scene::IMeshSceneNode *m_meshnode; + scene::IAnimatedMeshSceneNode *m_animated_meshnode; scene::IBillboardSceneNode *m_spritenode; + scene::ITextSceneNode* m_textnode; v3f m_position; v3f m_velocity; v3f m_acceleration; float m_yaw; s16 m_hp; - struct LuaEntityProperties *m_prop; SmoothTranslator pos_translator; // Spritesheet/animation stuff v2f m_tx_size; v2s16 m_tx_basepos; + bool m_initial_tx_basepos_set; bool m_tx_select_horiz_by_yawpitch; + v2f m_animation_range; + int m_animation_speed; + int m_animation_blend; + std::map > m_bone_position; // stores position and rotation for each bone name + std::string m_attachment_bone; + v3f m_attachment_position; + v3f m_attachment_rotation; + bool m_attached_to_local; int m_anim_frame; int m_anim_num_frames; float m_anim_framelength; float m_anim_timer; ItemGroupList m_armor_groups; float m_reset_textures_timer; + bool m_visuals_expired; + float m_step_distance_counter; + u8 m_last_light; + bool m_is_visible; public: - LuaEntityCAO(IGameDef *gamedef, ClientEnvironment *env): + GenericCAO(IGameDef *gamedef, ClientEnvironment *env): ClientActiveObject(0, gamedef, env), + // + m_is_player(false), + m_is_local_player(false), + m_id(0), + // m_smgr(NULL), + m_irr(NULL), m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.), m_meshnode(NULL), + m_animated_meshnode(NULL), m_spritenode(NULL), + m_textnode(NULL), m_position(v3f(0,10*BS,0)), m_velocity(v3f(0,0,0)), m_acceleration(v3f(0,0,0)), m_yaw(0), m_hp(1), - m_prop(new LuaEntityProperties), m_tx_size(1,1), m_tx_basepos(0,0), + m_initial_tx_basepos_set(false), m_tx_select_horiz_by_yawpitch(false), + m_animation_range(v2f(0,0)), + m_animation_speed(15), + m_animation_blend(0), + m_bone_position(std::map >()), + m_attachment_bone(""), + m_attachment_position(v3f(0,0,0)), + m_attachment_rotation(v3f(0,0,0)), + m_attached_to_local(false), m_anim_frame(0), m_anim_num_frames(1), m_anim_framelength(0.2), m_anim_timer(0), - m_reset_textures_timer(-1) + m_reset_textures_timer(-1), + m_visuals_expired(false), + m_step_distance_counter(0), + m_last_light(255), + m_is_visible(false) { if(gamedef == NULL) ClientActiveObject::registerType(getType(), create); } + bool getCollisionBox(aabb3f *toset) { + if (m_prop.physical) { + aabb3f retval; + //update collision box + toset->MinEdge = m_prop.collisionbox.MinEdge * BS; + toset->MaxEdge = m_prop.collisionbox.MaxEdge * BS; + + toset->MinEdge += m_position; + toset->MaxEdge += m_position; + + return true; + } + + return false; + } + + bool collideWithObjects() { + return m_prop.collideWithObjects; + } + void initialize(const std::string &data) { - infostream<<"LuaEntityCAO: Got init data"<deSerialize(prop_is); - - infostream<<"m_prop: "<dump()<collisionbox; - m_selection_box.MinEdge *= BS; - m_selection_box.MaxEdge *= BS; - - pos_translator.init(m_position); + } - m_tx_size.X = 1.0 / m_prop->spritediv.X; - m_tx_size.Y = 1.0 / m_prop->spritediv.Y; - m_tx_basepos.X = m_tx_size.X * m_prop->initial_sprite_basepos.X; - m_tx_basepos.Y = m_tx_size.Y * m_prop->initial_sprite_basepos.Y; - + for(int i=0; igetPlayer(m_name.c_str()); + if(player && player->isLocal()){ + m_is_local_player = true; + } + m_env->addPlayerName(m_name.c_str()); + } } - ~LuaEntityCAO() + ~GenericCAO() { - delete m_prop; + if(m_is_player){ + m_env->removePlayerName(m_name.c_str()); + } } static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env) { - return new LuaEntityCAO(gamedef, env); + return new GenericCAO(gamedef, env); } u8 getType() const { - return ACTIVEOBJECT_TYPE_LUAENTITY; + return ACTIVEOBJECT_TYPE_GENERIC; } core::aabbox3d* getSelectionBox() { + if(!m_prop.is_visible || !m_is_visible || m_is_local_player || getParent() != NULL) + return NULL; return &m_selection_box; } v3f getPosition() { + if(getParent() != NULL){ + if(m_meshnode) + return m_meshnode->getAbsolutePosition(); + if(m_animated_meshnode) + return m_animated_meshnode->getAbsolutePosition(); + if(m_spritenode) + return m_spritenode->getAbsolutePosition(); + return m_position; + } return pos_translator.vect_show; } - + + scene::IMeshSceneNode *getMeshSceneNode() + { + if(m_meshnode) + return m_meshnode; + return NULL; + } + + scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode() + { + if(m_animated_meshnode) + return m_animated_meshnode; + return NULL; + } + + scene::IBillboardSceneNode *getSpriteSceneNode() + { + if(m_spritenode) + return m_spritenode; + return NULL; + } + + bool isPlayer() + { + return m_is_player; + } + + bool isLocalPlayer() + { + return m_is_local_player; + } + + void setAttachments() + { + updateAttachments(); + } + + ClientActiveObject *getParent() + { + ClientActiveObject *obj = NULL; + for(std::vector >::const_iterator cii = m_env->attachment_list.begin(); cii != m_env->attachment_list.end(); cii++) + { + if(cii->X == getId()){ // This ID is our child + if(cii->Y > 0){ // A parent ID exists for our child + if(cii->X != cii->Y){ // The parent and child ID are not the same + obj = m_env->getActiveObject(cii->Y); + } + } + break; + } + } + if(obj) + return obj; + return NULL; + } + + void removeFromScene(bool permanent) + { + if(permanent) // Should be true when removing the object permanently and false when refreshing (eg: updating visuals) + { + // Detach this object's children + for(std::vector >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++) + { + if(ii->Y == getId()) // Is a child of our object + { + ii->Y = 0; + ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child + if(obj) + obj->setAttachments(); + } + } + // Delete this object from the attachments list + for(std::vector >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++) + { + if(ii->X == getId()) // Is our object + { + m_env->attachment_list.erase(ii); + break; + } + } + } + + if(m_meshnode){ + m_meshnode->remove(); + m_meshnode = NULL; + } + if(m_animated_meshnode){ + m_animated_meshnode->remove(); + m_animated_meshnode = NULL; + } + if(m_spritenode){ + m_spritenode->remove(); + m_spritenode = NULL; + } + } + void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, IrrlichtDevice *irr) { m_smgr = smgr; + m_irr = irr; - if(m_meshnode != NULL || m_spritenode != NULL) + if(m_meshnode != NULL || m_animated_meshnode != NULL || m_spritenode != NULL) return; + m_visuals_expired = false; + + if(!m_prop.is_visible || m_is_local_player) + return; + //video::IVideoDriver* driver = smgr->getVideoDriver(); - if(m_prop->visual == "sprite"){ - infostream<<"LuaEntityCAO::addToScene(): single_sprite"<addBillboardSceneNode( NULL, v2f(1, 1), v3f(0,0,0), -1); m_spritenode->setMaterialTexture(0, - tsrc->getTextureRaw("unknown_block.png")); + tsrc->getTexture("unknown_node.png")); m_spritenode->setMaterialFlag(video::EMF_LIGHTING, false); m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false); m_spritenode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF); m_spritenode->setMaterialFlag(video::EMF_FOG_ENABLE, true); - m_spritenode->setColor(video::SColor(255,0,0,0)); - m_spritenode->setVisible(false); /* Set visible when brightness is known */ - m_spritenode->setSize(m_prop->visual_size*BS); + u8 li = m_last_light; + m_spritenode->setColor(video::SColor(255,li,li,li)); + m_spritenode->setSize(m_prop.visual_size*BS); { const float txs = 1.0 / 1; const float tys = 1.0 / 1; setBillboardTextureMatrix(m_spritenode, txs, tys, 0, 0); } - } else if(m_prop->visual == "cube"){ - infostream<<"LuaEntityCAO::addToScene(): cube"<append(vertices, 4, indices, 6); + // Set material + buf->getMaterial().setFlag(video::EMF_LIGHTING, false); + buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); + buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true); + buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + // Add to mesh + mesh->addMeshBuffer(buf); + buf->drop(); + } + { // Back + scene::IMeshBuffer *buf = new scene::SMeshBuffer(); + u8 li = m_last_light; + video::SColor c(255,li,li,li); + video::S3DVertex vertices[4] = + { + video::S3DVertex(dx,-dy,0, 0,0,0, c, 1,1), + video::S3DVertex(-dx,-dy,0, 0,0,0, c, 0,1), + video::S3DVertex(-dx,dy,0, 0,0,0, c, 0,0), + video::S3DVertex(dx,dy,0, 0,0,0, c, 1,0), + }; + u16 indices[] = {0,1,2,2,3,0}; + buf->append(vertices, 4, indices, 6); + // Set material + buf->getMaterial().setFlag(video::EMF_LIGHTING, false); + buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); + buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true); + buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + // Add to mesh + mesh->addMeshBuffer(buf); + buf->drop(); + } + m_meshnode = smgr->addMeshSceneNode(mesh, NULL); + mesh->drop(); + // Set it to use the materials of the meshbuffers directly. + // This is needed for changing the texture in the future + m_meshnode->setReadOnlyMaterials(true); + } + else if(m_prop.visual == "cube"){ + infostream<<"GenericCAO::addToScene(): cube"<addMeshSceneNode(mesh, NULL); mesh->drop(); - m_meshnode->setScale(v3f(1)); - // Will be shown when we know the brightness - m_meshnode->setVisible(false); + m_meshnode->setScale(v3f(m_prop.visual_size.X, + m_prop.visual_size.Y, + m_prop.visual_size.X)); + u8 li = m_last_light; + setMeshColor(m_meshnode->getMesh(), video::SColor(255,li,li,li)); + + m_meshnode->setMaterialFlag(video::EMF_LIGHTING, false); + m_meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false); + m_meshnode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF); + m_meshnode->setMaterialFlag(video::EMF_FOG_ENABLE, true); + } + else if(m_prop.visual == "mesh"){ + infostream<<"GenericCAO::addToScene(): mesh"<getMesh(m_prop.mesh.c_str()); + if(mesh) + { + m_animated_meshnode = smgr->addAnimatedMeshSceneNode(mesh, NULL); + m_animated_meshnode->animateJoints(); // Needed for some animations + m_animated_meshnode->setScale(v3f(m_prop.visual_size.X, + m_prop.visual_size.Y, + m_prop.visual_size.X)); + u8 li = m_last_light; + setMeshColor(m_animated_meshnode->getMesh(), video::SColor(255,li,li,li)); + + m_animated_meshnode->setMaterialFlag(video::EMF_LIGHTING, false); + m_animated_meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false); + m_animated_meshnode->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF); + m_animated_meshnode->setMaterialFlag(video::EMF_FOG_ENABLE, true); + } + else + errorstream<<"GenericCAO::addToScene(): Could not load mesh "<= 1){ + infostream<<"textures[0]: "<idef(); + ItemStack item(m_prop.textures[0], 1, 0, "", idef); + scene::IMesh *item_mesh = idef->getWieldMesh(item.getDefinition(idef).name, m_gamedef); + + // Copy mesh to be able to set unique vertex colors + scene::IMeshManipulator *manip = + irr->getVideoDriver()->getMeshManipulator(); + scene::IMesh *mesh = manip->createMeshUniquePrimitives(item_mesh); + + m_meshnode = smgr->addMeshSceneNode(mesh, NULL); + mesh->drop(); + + m_meshnode->setScale(v3f(m_prop.visual_size.X/2, + m_prop.visual_size.Y/2, + m_prop.visual_size.X/2)); + u8 li = m_last_light; + setMeshColor(m_meshnode->getMesh(), video::SColor(255,li,li,li)); + } } else { - infostream<<"LuaEntityCAO::addToScene(): \""<visual + infostream<<"GenericCAO::addToScene(): \""<getGUIEnvironment(); + std::wstring wname = narrow_to_wide(m_name); + m_textnode = smgr->addTextSceneNode(gui->getBuiltInFont(), + wname.c_str(), video::SColor(255,255,255,255), node); + m_textnode->setPosition(v3f(0, BS*1.1, 0)); + } + updateNodePos(); + updateAnimation(); + updateBonePosition(); + updateAttachments(); } - void removeFromScene() + void expireVisuals() { - if(m_meshnode){ - m_meshnode->remove(); - m_meshnode = NULL; - } - if(m_spritenode){ - m_spritenode->remove(); - m_spritenode = NULL; - } + m_visuals_expired = true; } - + void updateLight(u8 light_at_pos) { - bool is_visible = (m_hp != 0); u8 li = decode_light(light_at_pos); - video::SColor color(255,li,li,li); - if(m_meshnode){ - setMeshColor(m_meshnode->getMesh(), color); - m_meshnode->setVisible(is_visible); - } - if(m_spritenode){ - m_spritenode->setColor(color); - m_spritenode->setVisible(is_visible); + if(li != m_last_light){ + m_last_light = li; + video::SColor color(255,li,li,li); + if(m_meshnode) + setMeshColor(m_meshnode->getMesh(), color); + if(m_animated_meshnode) + setMeshColor(m_animated_meshnode->getMesh(), color); + if(m_spritenode) + m_spritenode->setColor(color); } } @@ -728,8 +1054,20 @@ class LuaEntityCAO : public ClientActiveObject void updateNodePos() { + if(getParent() != NULL) + return; + if(m_meshnode){ m_meshnode->setPosition(pos_translator.vect_show); + v3f rot = m_meshnode->getRotation(); + rot.Y = -m_yaw; + m_meshnode->setRotation(rot); + } + if(m_animated_meshnode){ + m_animated_meshnode->setPosition(pos_translator.vect_show); + v3f rot = m_animated_meshnode->getRotation(); + rot.Y = -m_yaw; + m_animated_meshnode->setRotation(rot); } if(m_spritenode){ m_spritenode->setPosition(pos_translator.vect_show); @@ -738,33 +1076,117 @@ class LuaEntityCAO : public ClientActiveObject void step(float dtime, ClientEnvironment *env) { - if(m_prop->physical){ - core::aabbox3d box = m_prop->collisionbox; - box.MinEdge *= BS; - box.MaxEdge *= BS; - collisionMoveResult moveresult; - f32 pos_max_d = BS*0.25; // Distance per iteration - v3f p_pos = m_position; - v3f p_velocity = m_velocity; - IGameDef *gamedef = env->getGameDef(); - moveresult = collisionMovePrecise(&env->getMap(), gamedef, - pos_max_d, box, dtime, p_pos, p_velocity); - // Apply results - m_position = p_pos; - m_velocity = p_velocity; - - bool is_end_position = moveresult.collides; - pos_translator.update(m_position, is_end_position, dtime); - pos_translator.translate(dtime); - updateNodePos(); + if(m_visuals_expired && m_smgr && m_irr){ + m_visuals_expired = false; - m_velocity += dtime * m_acceleration; - } else { - m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration; - m_velocity += dtime * m_acceleration; - pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time); - pos_translator.translate(dtime); - updateNodePos(); + // Attachments, part 1: All attached objects must be unparented first, or Irrlicht causes a segmentation fault + for(std::vector >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++) + { + if(ii->Y == getId()) // This is a child of our parent + { + ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child + if(obj) + { + scene::IMeshSceneNode *m_child_meshnode = obj->getMeshSceneNode(); + scene::IAnimatedMeshSceneNode *m_child_animated_meshnode = obj->getAnimatedMeshSceneNode(); + scene::IBillboardSceneNode *m_child_spritenode = obj->getSpriteSceneNode(); + if(m_child_meshnode) + m_child_meshnode->setParent(m_smgr->getRootSceneNode()); + if(m_child_animated_meshnode) + m_child_animated_meshnode->setParent(m_smgr->getRootSceneNode()); + if(m_child_spritenode) + m_child_spritenode->setParent(m_smgr->getRootSceneNode()); + } + } + } + + removeFromScene(false); + addToScene(m_smgr, m_gamedef->tsrc(), m_irr); + + // Attachments, part 2: Now that the parent has been refreshed, put its attachments back + for(std::vector >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++) + { + if(ii->Y == getId()) // This is a child of our parent + { + ClientActiveObject *obj = m_env->getActiveObject(ii->X); // Get the object of the child + if(obj) + obj->setAttachments(); + } + } + } + + // Make sure m_is_visible is always applied + if(m_meshnode) + m_meshnode->setVisible(m_is_visible); + if(m_animated_meshnode) + m_animated_meshnode->setVisible(m_is_visible); + if(m_spritenode) + m_spritenode->setVisible(m_is_visible); + if(m_textnode) + m_textnode->setVisible(m_is_visible); + + if(getParent() != NULL) // Attachments should be glued to their parent by Irrlicht + { + // Set these for later + m_position = getPosition(); + m_velocity = v3f(0,0,0); + m_acceleration = v3f(0,0,0); + pos_translator.vect_show = m_position; + + if(m_is_local_player) // Update local player attachment position + { + LocalPlayer *player = m_env->getLocalPlayer(); + player->overridePosition = getParent()->getPosition(); + m_env->getLocalPlayer()->parent = getParent(); + } + } + else + { + v3f lastpos = pos_translator.vect_show; + + if(m_prop.physical){ + core::aabbox3d box = m_prop.collisionbox; + box.MinEdge *= BS; + box.MaxEdge *= BS; + collisionMoveResult moveresult; + f32 pos_max_d = BS*0.125; // Distance per iteration + v3f p_pos = m_position; + v3f p_velocity = m_velocity; + v3f p_acceleration = m_acceleration; + moveresult = collisionMoveSimple(env,env->getGameDef(), + pos_max_d, box, m_prop.stepheight, dtime, + p_pos, p_velocity, p_acceleration, + this, m_prop.collideWithObjects); + // Apply results + m_position = p_pos; + m_velocity = p_velocity; + m_acceleration = p_acceleration; + + bool is_end_position = moveresult.collides; + pos_translator.update(m_position, is_end_position, dtime); + pos_translator.translate(dtime); + updateNodePos(); + } else { + m_position += dtime * m_velocity + 0.5 * dtime * dtime * m_acceleration; + m_velocity += dtime * m_acceleration; + pos_translator.update(m_position, pos_translator.aim_is_end, pos_translator.anim_time); + pos_translator.translate(dtime); + updateNodePos(); + } + + float moved = lastpos.getDistanceFrom(pos_translator.vect_show); + m_step_distance_counter += moved; + if(m_step_distance_counter > 1.5*BS){ + m_step_distance_counter = 0; + if(!m_is_local_player && m_prop.makes_footstep_sound){ + INodeDefManager *ndef = m_gamedef->ndef(); + v3s16 p = floatToInt(getPosition() + v3f(0, + (m_prop.collisionbox.MinEdge.Y-0.5)*BS, 0), BS); + MapNode n = m_env->getMap().getNodeNoEx(p); + SimpleSoundSpec spec = ndef->get(n).sound_footstep; + m_gamedef->sound()->playSoundAt(spec, false, getPosition()); + } + } } m_anim_timer += dtime; @@ -784,6 +1206,16 @@ class LuaEntityCAO : public ClientActiveObject updateTextures(""); } } + if(getParent() == NULL && fabs(m_prop.automatic_rotate) > 0.001){ + m_yaw += dtime * m_prop.automatic_rotate * 180 / M_PI; + updateNodePos(); + } + + if (getParent() == NULL && m_prop.automatic_face_movement_dir && + (fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001)){ + m_yaw = atan2(m_velocity.Z,m_velocity.X) * 180 / M_PI + m_prop.automatic_face_movement_dir_offset; + updateNodePos(); + } } void updateTexturePos() @@ -807,7 +1239,7 @@ class LuaEntityCAO : public ClientActiveObject else if(cam_to_entity.Y < -0.75) col += 4; else{ - float mob_dir = atan2(cam_to_entity.Z, cam_to_entity.X) / PI * 180.; + float mob_dir = atan2(cam_to_entity.Z, cam_to_entity.X) / M_PI * 180.; float dir = mob_dir - m_yaw; dir = wrapDegrees_180(dir); //infostream<<"id="<textures.size() >= 1) - texturestring = m_prop->textures[0]; - texturestring += mod; - m_spritenode->setMaterialTexture(0, - tsrc->getTextureRaw(texturestring)); - } - if(m_meshnode){ - for (u32 i = 0; i < 6; ++i) + bool use_trilinear_filter = g_settings->getBool("trilinear_filter"); + bool use_bilinear_filter = g_settings->getBool("bilinear_filter"); + bool use_anisotropic_filter = g_settings->getBool("anisotropic_filter"); + + if(m_spritenode) + { + if(m_prop.visual == "sprite") { - std::string texturestring = "unknown_block.png"; - if(m_prop->textures.size() > i) - texturestring = m_prop->textures[i]; + std::string texturestring = "unknown_node.png"; + if(m_prop.textures.size() >= 1) + texturestring = m_prop.textures[0]; texturestring += mod; - AtlasPointer ap = tsrc->getTexture(texturestring); - - // Get the tile texture and atlas transformation - video::ITexture* atlas = ap.atlas; - v2f pos = ap.pos; - v2f size = ap.size; - - // Set material flags and texture - video::SMaterial& material = m_meshnode->getMaterial(i); - material.setFlag(video::EMF_LIGHTING, false); - material.setFlag(video::EMF_BILINEAR_FILTER, false); - material.setTexture(0, atlas); - material.getTextureMatrix(0).setTextureTranslate(pos.X, pos.Y); - material.getTextureMatrix(0).setTextureScale(size.X, size.Y); + m_spritenode->setMaterialTexture(0, + tsrc->getTexture(texturestring)); + + // This allows setting per-material colors. However, until a real lighting + // system is added, the code below will have no effect. Once MineTest + // has directional lighting, it should work automatically. + if(m_prop.colors.size() >= 1) + { + m_spritenode->getMaterial(0).AmbientColor = m_prop.colors[0]; + m_spritenode->getMaterial(0).DiffuseColor = m_prop.colors[0]; + m_spritenode->getMaterial(0).SpecularColor = m_prop.colors[0]; + } + + m_spritenode->getMaterial(0).setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter); + m_spritenode->getMaterial(0).setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter); + m_spritenode->getMaterial(0).setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter); + } + } + if(m_animated_meshnode) + { + if(m_prop.visual == "mesh") + { + for (u32 i = 0; i < m_prop.textures.size() && i < m_animated_meshnode->getMaterialCount(); ++i) + { + std::string texturestring = m_prop.textures[i]; + if(texturestring == "") + continue; // Empty texture string means don't modify that material + texturestring += mod; + video::ITexture* texture = tsrc->getTexture(texturestring); + if(!texture) + { + errorstream<<"GenericCAO::updateTextures(): Could not load texture "<getMaterial(i); + material.TextureLayer[0].Texture = texture; + material.setFlag(video::EMF_LIGHTING, false); + material.setFlag(video::EMF_BILINEAR_FILTER, false); + + m_animated_meshnode->getMaterial(i).setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter); + m_animated_meshnode->getMaterial(i).setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter); + m_animated_meshnode->getMaterial(i).setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter); + } + for (u32 i = 0; i < m_prop.colors.size() && i < m_animated_meshnode->getMaterialCount(); ++i) + { + // This allows setting per-material colors. However, until a real lighting + // system is added, the code below will have no effect. Once MineTest + // has directional lighting, it should work automatically. + m_animated_meshnode->getMaterial(i).AmbientColor = m_prop.colors[i]; + m_animated_meshnode->getMaterial(i).DiffuseColor = m_prop.colors[i]; + m_animated_meshnode->getMaterial(i).SpecularColor = m_prop.colors[i]; + } + } + } + if(m_meshnode) + { + if(m_prop.visual == "cube") + { + for (u32 i = 0; i < 6; ++i) + { + std::string texturestring = "unknown_node.png"; + if(m_prop.textures.size() > i) + texturestring = m_prop.textures[i]; + texturestring += mod; + + + // Set material flags and texture + video::SMaterial& material = m_meshnode->getMaterial(i); + material.setFlag(video::EMF_LIGHTING, false); + material.setFlag(video::EMF_BILINEAR_FILTER, false); + material.setTexture(0, + tsrc->getTexture(texturestring)); + material.getTextureMatrix(0).makeIdentity(); + + // This allows setting per-material colors. However, until a real lighting + // system is added, the code below will have no effect. Once MineTest + // has directional lighting, it should work automatically. + if(m_prop.colors.size() > i) + { + m_meshnode->getMaterial(i).AmbientColor = m_prop.colors[i]; + m_meshnode->getMaterial(i).DiffuseColor = m_prop.colors[i]; + m_meshnode->getMaterial(i).SpecularColor = m_prop.colors[i]; + } + + m_meshnode->getMaterial(i).setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter); + m_meshnode->getMaterial(i).setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter); + m_meshnode->getMaterial(i).setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter); + } + } + else if(m_prop.visual == "upright_sprite") + { + scene::IMesh *mesh = m_meshnode->getMesh(); + { + std::string tname = "unknown_object.png"; + if(m_prop.textures.size() >= 1) + tname = m_prop.textures[0]; + tname += mod; + scene::IMeshBuffer *buf = mesh->getMeshBuffer(0); + buf->getMaterial().setTexture(0, + tsrc->getTexture(tname)); + + // This allows setting per-material colors. However, until a real lighting + // system is added, the code below will have no effect. Once MineTest + // has directional lighting, it should work automatically. + if(m_prop.colors.size() >= 1) + { + buf->getMaterial().AmbientColor = m_prop.colors[0]; + buf->getMaterial().DiffuseColor = m_prop.colors[0]; + buf->getMaterial().SpecularColor = m_prop.colors[0]; + } + + buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter); + buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter); + buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter); + } + { + std::string tname = "unknown_object.png"; + if(m_prop.textures.size() >= 2) + tname = m_prop.textures[1]; + else if(m_prop.textures.size() >= 1) + tname = m_prop.textures[0]; + tname += mod; + scene::IMeshBuffer *buf = mesh->getMeshBuffer(1); + buf->getMaterial().setTexture(0, + tsrc->getTexture(tname)); + + // This allows setting per-material colors. However, until a real lighting + // system is added, the code below will have no effect. Once MineTest + // has directional lighting, it should work automatically. + if(m_prop.colors.size() >= 2) + { + buf->getMaterial().AmbientColor = m_prop.colors[1]; + buf->getMaterial().DiffuseColor = m_prop.colors[1]; + buf->getMaterial().SpecularColor = m_prop.colors[1]; + } + else if(m_prop.colors.size() >= 1) + { + buf->getMaterial().AmbientColor = m_prop.colors[0]; + buf->getMaterial().DiffuseColor = m_prop.colors[0]; + buf->getMaterial().SpecularColor = m_prop.colors[0]; + } + + buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter); + buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter); + buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter); + } + } + } + } + + void updateAnimation() + { + if(m_animated_meshnode == NULL) + return; + + m_animated_meshnode->setFrameLoop((int)m_animation_range.X, (int)m_animation_range.Y); + m_animated_meshnode->setAnimationSpeed(m_animation_speed); + m_animated_meshnode->setTransitionTime(m_animation_blend); + } + + void updateBonePosition() + { + if(!m_bone_position.size() || m_animated_meshnode == NULL) + return; + + m_animated_meshnode->setJointMode(irr::scene::EJUOR_CONTROL); // To write positions to the mesh on render + for(std::map >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii){ + std::string bone_name = (*ii).first; + v3f bone_pos = (*ii).second.X; + v3f bone_rot = (*ii).second.Y; + irr::scene::IBoneSceneNode* bone = m_animated_meshnode->getJointNode(bone_name.c_str()); + if(bone) + { + bone->setPosition(bone_pos); + bone->setRotation(bone_rot); + } + } + } + + void updateAttachments() + { + m_attached_to_local = getParent() != NULL && getParent()->isLocalPlayer(); + m_is_visible = !m_attached_to_local; // Objects attached to the local player should always be hidden + + if(getParent() == NULL || m_attached_to_local) // Detach or don't attach + { + if(m_meshnode) + { + v3f old_position = m_meshnode->getAbsolutePosition(); + v3f old_rotation = m_meshnode->getRotation(); + m_meshnode->setParent(m_smgr->getRootSceneNode()); + m_meshnode->setPosition(old_position); + m_meshnode->setRotation(old_rotation); + m_meshnode->updateAbsolutePosition(); + } + if(m_animated_meshnode) + { + v3f old_position = m_animated_meshnode->getAbsolutePosition(); + v3f old_rotation = m_animated_meshnode->getRotation(); + m_animated_meshnode->setParent(m_smgr->getRootSceneNode()); + m_animated_meshnode->setPosition(old_position); + m_animated_meshnode->setRotation(old_rotation); + m_animated_meshnode->updateAbsolutePosition(); + } + if(m_spritenode) + { + v3f old_position = m_spritenode->getAbsolutePosition(); + v3f old_rotation = m_spritenode->getRotation(); + m_spritenode->setParent(m_smgr->getRootSceneNode()); + m_spritenode->setPosition(old_position); + m_spritenode->setRotation(old_rotation); + m_spritenode->updateAbsolutePosition(); + } + if(m_is_local_player) + { + LocalPlayer *player = m_env->getLocalPlayer(); + player->isAttached = false; + } + } + else // Attach + { + scene::IMeshSceneNode *parent_mesh = NULL; + if(getParent()->getMeshSceneNode()) + parent_mesh = getParent()->getMeshSceneNode(); + scene::IAnimatedMeshSceneNode *parent_animated_mesh = NULL; + if(getParent()->getAnimatedMeshSceneNode()) + parent_animated_mesh = getParent()->getAnimatedMeshSceneNode(); + scene::IBillboardSceneNode *parent_sprite = NULL; + if(getParent()->getSpriteSceneNode()) + parent_sprite = getParent()->getSpriteSceneNode(); + + scene::IBoneSceneNode *parent_bone = NULL; + if(parent_animated_mesh && m_attachment_bone != "") + parent_bone = parent_animated_mesh->getJointNode(m_attachment_bone.c_str()); + + // The spaghetti code below makes sure attaching works if either the parent or child is a spritenode, meshnode, or animatedmeshnode + // TODO: Perhaps use polymorphism here to save code duplication + if(m_meshnode){ + if(parent_bone){ + m_meshnode->setParent(parent_bone); + m_meshnode->setPosition(m_attachment_position); + m_meshnode->setRotation(m_attachment_rotation); + m_meshnode->updateAbsolutePosition(); + } + else + { + if(parent_mesh){ + m_meshnode->setParent(parent_mesh); + m_meshnode->setPosition(m_attachment_position); + m_meshnode->setRotation(m_attachment_rotation); + m_meshnode->updateAbsolutePosition(); + } + else if(parent_animated_mesh){ + m_meshnode->setParent(parent_animated_mesh); + m_meshnode->setPosition(m_attachment_position); + m_meshnode->setRotation(m_attachment_rotation); + m_meshnode->updateAbsolutePosition(); + } + else if(parent_sprite){ + m_meshnode->setParent(parent_sprite); + m_meshnode->setPosition(m_attachment_position); + m_meshnode->setRotation(m_attachment_rotation); + m_meshnode->updateAbsolutePosition(); + } + } + } + if(m_animated_meshnode){ + if(parent_bone){ + m_animated_meshnode->setParent(parent_bone); + m_animated_meshnode->setPosition(m_attachment_position); + m_animated_meshnode->setRotation(m_attachment_rotation); + m_animated_meshnode->updateAbsolutePosition(); + } + else + { + if(parent_mesh){ + m_animated_meshnode->setParent(parent_mesh); + m_animated_meshnode->setPosition(m_attachment_position); + m_animated_meshnode->setRotation(m_attachment_rotation); + m_animated_meshnode->updateAbsolutePosition(); + } + else if(parent_animated_mesh){ + m_animated_meshnode->setParent(parent_animated_mesh); + m_animated_meshnode->setPosition(m_attachment_position); + m_animated_meshnode->setRotation(m_attachment_rotation); + m_animated_meshnode->updateAbsolutePosition(); + } + else if(parent_sprite){ + m_animated_meshnode->setParent(parent_sprite); + m_animated_meshnode->setPosition(m_attachment_position); + m_animated_meshnode->setRotation(m_attachment_rotation); + m_animated_meshnode->updateAbsolutePosition(); + } + } + } + if(m_spritenode){ + if(parent_bone){ + m_spritenode->setParent(parent_bone); + m_spritenode->setPosition(m_attachment_position); + m_spritenode->setRotation(m_attachment_rotation); + m_spritenode->updateAbsolutePosition(); + } + else + { + if(parent_mesh){ + m_spritenode->setParent(parent_mesh); + m_spritenode->setPosition(m_attachment_position); + m_spritenode->setRotation(m_attachment_rotation); + m_spritenode->updateAbsolutePosition(); + } + else if(parent_animated_mesh){ + m_spritenode->setParent(parent_animated_mesh); + m_spritenode->setPosition(m_attachment_position); + m_spritenode->setRotation(m_attachment_rotation); + m_spritenode->updateAbsolutePosition(); + } + else if(parent_sprite){ + m_spritenode->setParent(parent_sprite); + m_spritenode->setPosition(m_attachment_position); + m_spritenode->setRotation(m_attachment_rotation); + m_spritenode->updateAbsolutePosition(); + } + } + } + if(m_is_local_player) + { + LocalPlayer *player = m_env->getLocalPlayer(); + player->isAttached = true; } } } void processMessage(const std::string &data) { - //infostream<<"LuaEntityCAO: Got message"<physical) + if(!m_prop.physical) pos_translator.update(m_position, is_end_position, update_interval); } else { pos_translator.init(m_position); } updateNodePos(); } - else if(cmd == LUAENTITY_CMD_SET_TEXTURE_MOD) // set texture modification + else if(cmd == GENERIC_CMD_SET_TEXTURE_MOD) { std::string mod = deSerializeString(is); updateTextures(mod); } - else if(cmd == LUAENTITY_CMD_SET_SPRITE) // set sprite + else if(cmd == GENERIC_CMD_SET_SPRITE) { v2s16 p = readV2S16(is); int num_frames = readU16(is); @@ -921,15 +1690,89 @@ class LuaEntityCAO : public ClientActiveObject updateTexturePos(); } - else if(cmd == LUAENTITY_CMD_PUNCHED) + else if(cmd == GENERIC_CMD_SET_PHYSICS_OVERRIDE) + { + float override_speed = readF1000(is); + float override_jump = readF1000(is); + float override_gravity = readF1000(is); + // these are sent inverted so we get true when the server sends nothing + bool sneak = !readU8(is); + bool sneak_glitch = !readU8(is); + + if(m_is_local_player) + { + LocalPlayer *player = m_env->getLocalPlayer(); + player->physics_override_speed = override_speed; + player->physics_override_jump = override_jump; + player->physics_override_gravity = override_gravity; + player->physics_override_sneak = sneak; + player->physics_override_sneak_glitch = sneak_glitch; + } + } + else if(cmd == GENERIC_CMD_SET_ANIMATION) + { + m_animation_range = readV2F1000(is); + m_animation_speed = readF1000(is); + m_animation_blend = readF1000(is); + + updateAnimation(); + } + else if(cmd == GENERIC_CMD_SET_BONE_POSITION) + { + std::string bone = deSerializeString(is); + v3f position = readV3F1000(is); + v3f rotation = readV3F1000(is); + m_bone_position[bone] = core::vector2d(position, rotation); + + updateBonePosition(); + } + else if(cmd == GENERIC_CMD_SET_ATTACHMENT) + { + // If an entry already exists for this object, delete it first to avoid duplicates + for(std::vector >::iterator ii = m_env->attachment_list.begin(); ii != m_env->attachment_list.end(); ii++) + { + if(ii->X == getId()) // This is the ID of our object + { + m_env->attachment_list.erase(ii); + break; + } + } + m_env->attachment_list.push_back(core::vector2d(getId(), readS16(is))); + m_attachment_bone = deSerializeString(is); + m_attachment_position = readV3F1000(is); + m_attachment_rotation = readV3F1000(is); + + updateAttachments(); + } + else if(cmd == GENERIC_CMD_PUNCHED) { /*s16 damage =*/ readS16(is); s16 result_hp = readS16(is); - + + // Use this instead of the send damage to not interfere with prediction + s16 damage = m_hp - result_hp; + m_hp = result_hp; - // TODO: Execute defined fast response + + if (damage > 0) { + if (m_hp <= 0) { + // TODO: Execute defined fast response + // As there is no definition, make a smoke puff + ClientSimpleObject *simple = createSmokePuff( + m_smgr, m_env, m_position, + m_prop.visual_size * BS); + m_env->addSimpleObject(simple); + } else { + // TODO: Execute defined fast response + // Flashing shall suffice as there is no definition + m_reset_textures_timer = 0.05; + if(damage >= 2) + m_reset_textures_timer += 0.05 * damage; + updateTextures("^[brighten"); + } + } } - else if(cmd == LUAENTITY_CMD_UPDATE_ARMOR_GROUPS) + else if(cmd == GENERIC_CMD_UPDATE_ARMOR_GROUPS) { m_armor_groups.clear(); int armor_groups_size = readU16(is); @@ -952,7 +1795,7 @@ class LuaEntityCAO : public ClientActiveObject toolcap, punchitem, time_from_last_punch); - + if(result.did_punch && result.damage != 0) { if(result.damage < m_hp){ @@ -963,13 +1806,15 @@ class LuaEntityCAO : public ClientActiveObject // As there is no definition, make a smoke puff ClientSimpleObject *simple = createSmokePuff( m_smgr, m_env, m_position, - m_prop->visual_size * BS); + m_prop.visual_size * BS); m_env->addSimpleObject(simple); } // TODO: Execute defined fast response // Flashing shall suffice as there is no definition + m_reset_textures_timer = 0.05; + if(result.damage >= 2) + m_reset_textures_timer += 0.05 * result.damage; updateTextures("^[brighten"); - m_reset_textures_timer = 0.1; } return false; @@ -978,7 +1823,7 @@ class LuaEntityCAO : public ClientActiveObject std::string debugInfoText() { std::ostringstream os(std::ios::binary); - os<<"LuaEntityCAO hp="< m_selection_box; - scene::IMeshSceneNode *m_node; - scene::ITextSceneNode* m_text; - std::string m_name; - v3f m_position; - float m_yaw; - SmoothTranslator pos_translator; - bool m_is_local_player; - LocalPlayer *m_local_player; - float m_damage_visual_timer; - bool m_dead; - float m_step_distance_counter; - -public: - PlayerCAO(IGameDef *gamedef, ClientEnvironment *env): - ClientActiveObject(0, gamedef, env), - m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2.0,BS/3.), - m_node(NULL), - m_text(NULL), - m_position(v3f(0,10*BS,0)), - m_yaw(0), - m_is_local_player(false), - m_local_player(NULL), - m_damage_visual_timer(0), - m_dead(false), - m_step_distance_counter(0) - { - if(gamedef == NULL) - ClientActiveObject::registerType(getType(), create); - } - - void initialize(const std::string &data) - { - infostream<<"PlayerCAO: Got init data"<getPlayer(m_name.c_str()); - if(player && player->isLocal()){ - m_is_local_player = true; - m_local_player = (LocalPlayer*)player; - } - } - - ~PlayerCAO() - { - if(m_node) - m_node->remove(); - } - - static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env) - { - return new PlayerCAO(gamedef, env); - } - - u8 getType() const - { - return ACTIVEOBJECT_TYPE_PLAYER; - } - core::aabbox3d* getSelectionBox() - { - if(m_is_local_player) - return NULL; - if(m_dead) - return NULL; - return &m_selection_box; - } - v3f getPosition() - { - return pos_translator.vect_show; - } - - void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, - IrrlichtDevice *irr) - { - if(m_node != NULL) - return; - if(m_is_local_player) - return; - - //video::IVideoDriver* driver = smgr->getVideoDriver(); - gui::IGUIEnvironment* gui = irr->getGUIEnvironment(); - - scene::SMesh *mesh = new scene::SMesh(); - { // Front - scene::IMeshBuffer *buf = new scene::SMeshBuffer(); - video::SColor c(255,255,255,255); - video::S3DVertex vertices[4] = - { - video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1), - video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1), - video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0), - video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0), - }; - u16 indices[] = {0,1,2,2,3,0}; - buf->append(vertices, 4, indices, 6); - // Set material - buf->getMaterial().setFlag(video::EMF_LIGHTING, false); - buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); - buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true); - buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - // Add to mesh - mesh->addMeshBuffer(buf); - buf->drop(); - } - { // Back - scene::IMeshBuffer *buf = new scene::SMeshBuffer(); - video::SColor c(255,255,255,255); - video::S3DVertex vertices[4] = - { - video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1), - video::S3DVertex(-BS/2,0,0, 0,0,0, c, 0,1), - video::S3DVertex(-BS/2,BS*2,0, 0,0,0, c, 0,0), - video::S3DVertex(BS/2,BS*2,0, 0,0,0, c, 1,0), - }; - u16 indices[] = {0,1,2,2,3,0}; - buf->append(vertices, 4, indices, 6); - // Set material - buf->getMaterial().setFlag(video::EMF_LIGHTING, false); - buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); - buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true); - buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; - // Add to mesh - mesh->addMeshBuffer(buf); - buf->drop(); - } - m_node = smgr->addMeshSceneNode(mesh, NULL); - mesh->drop(); - // Set it to use the materials of the meshbuffers directly. - // This is needed for changing the texture in the future - m_node->setReadOnlyMaterials(true); - updateNodePos(); - - // Add a text node for showing the name - std::wstring wname = narrow_to_wide(m_name); - m_text = smgr->addTextSceneNode(gui->getBuiltInFont(), - wname.c_str(), video::SColor(255,255,255,255), m_node); - m_text->setPosition(v3f(0, (f32)BS*2.1, 0)); - - updateTextures(""); - updateVisibility(); - updateNodePos(); - } - - void removeFromScene() - { - if(m_node == NULL) - return; - - m_node->remove(); - m_node = NULL; - } - - void updateLight(u8 light_at_pos) - { - if(m_node == NULL) - return; - - u8 li = decode_light(light_at_pos); - video::SColor color(255,li,li,li); - setMeshColor(m_node->getMesh(), color); - - updateVisibility(); - } - - v3s16 getLightPosition() - { - return floatToInt(m_position+v3f(0,BS*1.5,0), BS); - } - - void updateVisibility() - { - if(m_node == NULL) - return; - - m_node->setVisible(!m_dead); - } - - void updateNodePos() - { - if(m_node == NULL) - return; - - m_node->setPosition(pos_translator.vect_show); - - v3f rot = m_node->getRotation(); - rot.Y = -m_yaw; - m_node->setRotation(rot); - } - - void step(float dtime, ClientEnvironment *env) - { - v3f lastpos = pos_translator.vect_show; - pos_translator.translate(dtime); - float moved = lastpos.getDistanceFrom(pos_translator.vect_show); - updateVisibility(); - updateNodePos(); - - if(m_damage_visual_timer > 0){ - m_damage_visual_timer -= dtime; - if(m_damage_visual_timer <= 0){ - updateTextures(""); - } - } - - m_step_distance_counter += moved; - if(m_step_distance_counter > 1.5*BS){ - m_step_distance_counter = 0; - if(!m_is_local_player){ - INodeDefManager *ndef = m_gamedef->ndef(); - v3s16 p = floatToInt(getPosition()+v3f(0,-0.5*BS, 0), BS); - MapNode n = m_env->getMap().getNodeNoEx(p); - SimpleSoundSpec spec = ndef->get(n).sound_footstep; - m_gamedef->sound()->playSoundAt(spec, false, getPosition()); - } - } - } - - void processMessage(const std::string &data) - { - //infostream<<"PlayerCAO: Got message"<= 2) - m_damage_visual_timer += 0.05 * damage; - updateTextures("^[brighten"); - } - else if(cmd == 2) // died or respawned - { - m_dead = readU8(is); - updateVisibility(); - } - } - - void updateTextures(const std::string &mod) - { - if(!m_node) - return; - ITextureSource *tsrc = m_gamedef->tsrc(); - scene::IMesh *mesh = m_node->getMesh(); - if(mesh){ - { - std::string tname = "player.png"; - tname += mod; - scene::IMeshBuffer *buf = mesh->getMeshBuffer(0); - buf->getMaterial().setTexture(0, - tsrc->getTextureRaw(tname)); - } - { - std::string tname = "player_back.png"; - tname += mod; - scene::IMeshBuffer *buf = mesh->getMeshBuffer(1); - buf->getMaterial().setTexture(0, - tsrc->getTextureRaw(tname)); - } - } - } -}; - -// Prototype -PlayerCAO proto_PlayerCAO(NULL, NULL); +GenericCAO proto_GenericCAO(NULL, NULL);