diff --git a/doc/lua_api.txt b/doc/lua_api.txt index c09a5815..caa5514b 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -611,6 +611,7 @@ methods: - get_wield_index(): returns the index of the wielded item - get_wielded_item() -> ItemStack - set_wielded_item(item): replaces the wielded item, returns true if successful +- set_armor_groups({group1=rating, group2=rating, ...}) LuaEntitySAO-only: (no-op for other objects) - setvelocity({x=num, y=num, z=num}) - getvelocity() -> {x=num, y=num, z=num} @@ -623,7 +624,6 @@ LuaEntitySAO-only: (no-op for other objects) - select_horiz_by_yawpitch=false) - ^ Select sprite from spritesheet with optional animation and DM-style - texture selection based on yaw relative to camera -- set_armor_groups({group1=rating, group2=rating, ...}) - get_entity_name() (DEPRECATED: Will be removed in a future version) - get_luaentity() Player-only: (no-op for other objects) diff --git a/src/content_cao.cpp b/src/content_cao.cpp index da4ab614..ba2011a5 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -39,6 +39,8 @@ with this program; if not, write to the Free Software Foundation, Inc., class Settings; struct ToolCapabilities; +#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" + core::map ClientActiveObject::m_types; /* @@ -532,823 +534,6 @@ void ItemCAO::initialize(const std::string &data) updateInfoText(); } -/* - LuaEntityCAO -*/ - -#include "luaentity_common.h" - -class LuaEntityCAO : public ClientActiveObject -{ -private: - scene::ISceneManager *m_smgr; - core::aabbox3d m_selection_box; - scene::IMeshSceneNode *m_meshnode; - scene::IBillboardSceneNode *m_spritenode; - 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_tx_select_horiz_by_yawpitch; - 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; - -public: - LuaEntityCAO(IGameDef *gamedef, ClientEnvironment *env): - ClientActiveObject(0, gamedef, env), - m_smgr(NULL), - m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.), - m_meshnode(NULL), - m_spritenode(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_tx_select_horiz_by_yawpitch(false), - m_anim_frame(0), - m_anim_num_frames(1), - m_anim_framelength(0.2), - m_anim_timer(0), - m_reset_textures_timer(-1) - { - if(gamedef == NULL) - ClientActiveObject::registerType(getType(), create); - } - - 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; - - updateNodePos(); - } - - ~LuaEntityCAO() - { - delete m_prop; - } - - static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env) - { - return new LuaEntityCAO(gamedef, env); - } - - u8 getType() const - { - return ACTIVEOBJECT_TYPE_LUAENTITY; - } - core::aabbox3d* getSelectionBox() - { - return &m_selection_box; - } - v3f getPosition() - { - return pos_translator.vect_show; - } - - void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, - IrrlichtDevice *irr) - { - m_smgr = smgr; - - if(m_meshnode != NULL || m_spritenode != NULL) - 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")); - 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); - { - 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"<addMeshSceneNode(mesh, NULL); - mesh->drop(); - - m_meshnode->setScale(v3f(1)); - // Will be shown when we know the brightness - m_meshnode->setVisible(false); - } else { - infostream<<"LuaEntityCAO::addToScene(): \""<visual - <<"\" not supported"<remove(); - m_meshnode = NULL; - } - if(m_spritenode){ - m_spritenode->remove(); - m_spritenode = NULL; - } - } - - 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); - } - } - - v3s16 getLightPosition() - { - return floatToInt(m_position, BS); - } - - void updateNodePos() - { - if(m_meshnode){ - m_meshnode->setPosition(pos_translator.vect_show); - } - if(m_spritenode){ - m_spritenode->setPosition(pos_translator.vect_show); - } - } - - 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(); - - 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(); - } - - m_anim_timer += dtime; - if(m_anim_timer >= m_anim_framelength){ - m_anim_timer -= m_anim_framelength; - m_anim_frame++; - if(m_anim_frame >= m_anim_num_frames) - m_anim_frame = 0; - } - - updateTexturePos(); - - if(m_reset_textures_timer >= 0){ - m_reset_textures_timer -= dtime; - if(m_reset_textures_timer <= 0){ - m_reset_textures_timer = -1; - updateTextures(""); - } - } - } - - void updateTexturePos() - { - if(m_spritenode){ - scene::ICameraSceneNode* camera = - m_spritenode->getSceneManager()->getActiveCamera(); - if(!camera) - return; - v3f cam_to_entity = m_spritenode->getAbsolutePosition() - - camera->getAbsolutePosition(); - cam_to_entity.normalize(); - - int row = m_tx_basepos.Y; - int col = m_tx_basepos.X; - - if(m_tx_select_horiz_by_yawpitch) - { - if(cam_to_entity.Y > 0.75) - col += 5; - 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 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) - { - std::string texturestring = "unknown_block.png"; - if(m_prop->textures.size() > i) - texturestring = m_prop->textures[i]; - 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); - } - } - } - - void processMessage(const std::string &data) - { - //infostream<<"LuaEntityCAO: Got message"<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 - { - std::string mod = deSerializeString(is); - updateTextures(mod); - } - else if(cmd == LUAENTITY_CMD_SET_SPRITE) // set sprite - { - v2s16 p = readV2S16(is); - int num_frames = readU16(is); - float framelength = readF1000(is); - bool select_horiz_by_yawpitch = readU8(is); - - m_tx_basepos = p; - m_anim_num_frames = num_frames; - m_anim_framelength = framelength; - m_tx_select_horiz_by_yawpitch = select_horiz_by_yawpitch; - - updateTexturePos(); - } - else if(cmd == LUAENTITY_CMD_PUNCHED) - { - /*s16 damage =*/ readS16(is); - s16 result_hp = readS16(is); - - m_hp = result_hp; - // TODO: Execute defined fast response - } - else if(cmd == LUAENTITY_CMD_UPDATE_ARMOR_GROUPS) - { - m_armor_groups.clear(); - int armor_groups_size = readU16(is); - for(int i=0; igetToolCapabilities(m_gamedef->idef()); - PunchDamageResult result = getPunchDamage( - m_armor_groups, - toolcap, - punchitem, - time_from_last_punch); - - if(result.did_punch && result.damage != 0) - { - if(result.damage < m_hp){ - m_hp -= result.damage; - } else { - 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); - } - // TODO: Execute defined fast response - // Flashing shall suffice as there is no definition - updateTextures("^[brighten"); - m_reset_textures_timer = 0.1; - } - - return false; - } - - std::string debugInfoText() - { - std::ostringstream os(std::ios::binary); - os<<"LuaEntityCAO hp="<first<<"="<second<<", "; - } - os<<"}"; - return os.str(); - } -}; - -// Prototype -LuaEntityCAO proto_LuaEntityCAO(NULL, NULL); - -/* - PlayerCAO -*/ - -class PlayerCAO : public ClientActiveObject -{ -private: - core::aabbox3d 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; - std::string m_wielded_item; - -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), - m_wielded_item("") - { - 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(); - } - else if(cmd == 3) // wielded item - { - m_wielded_item = deSerializeString(is); - updateWieldedItem(); - } - } - - 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)); - } - } - } - - void updateWieldedItem() - { - if(m_is_local_player) - { - // ignoring player item for local player - return; - } - - ItemStack item; - try - { - item.deSerialize(m_wielded_item, m_gamedef->idef()); - } - catch(SerializationError &e) - { - errorstream<<"PlayerCAO: SerializationError " - "while reading wielded item: " - <getPlayer(m_name.c_str()); - if(player) - { - InventoryList *inv = player->inventory.getList("main"); - assert(inv); - inv->changeItem(0, item); - } - - if(item.empty()) - { - infostream<<"PlayerCAO: empty player item for player " - < m_textures; v2s16 m_spritediv; + bool m_is_visible; + bool m_makes_footstep_sound; // scene::ISceneManager *m_smgr; + IrrlichtDevice *m_irr; core::aabbox3d m_selection_box; scene::IMeshSceneNode *m_meshnode; scene::IBillboardSceneNode *m_spritenode; + scene::ITextSceneNode* m_textnode; v3f m_position; v3f m_velocity; v3f m_acceleration; @@ -1388,11 +581,16 @@ private: float m_anim_timer; ItemGroupList m_armor_groups; float m_reset_textures_timer; + bool m_visuals_expired; + float m_step_distance_counter; public: GenericCAO(IGameDef *gamedef, ClientEnvironment *env): ClientActiveObject(0, gamedef, env), // + m_is_player(false), + m_is_local_player(false), + // m_hp_max(1), m_physical(false), m_weight(5), @@ -1400,11 +598,15 @@ public: m_visual("sprite"), m_visual_size(1,1), m_spritediv(1,1), + m_is_visible(true), + m_makes_footstep_sound(false), // 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_spritenode(NULL), + m_textnode(NULL), m_position(v3f(0,10*BS,0)), m_velocity(v3f(0,0,0)), m_acceleration(v3f(0,0,0)), @@ -1417,7 +619,9 @@ public: 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_textures.push_back("unknown_object.png"); if(gamedef == NULL) @@ -1427,23 +631,36 @@ public: void initialize(const std::string &data) { infostream<<"GenericCAO: Got init data"<getPlayer(m_name.c_str()); + if(player && player->isLocal()){ + m_is_local_player = true; + } + } } ~GenericCAO() @@ -1461,6 +678,8 @@ public: } core::aabbox3d* getSelectionBox() { + if(!m_is_visible || m_is_local_player) + return NULL; return &m_selection_box; } v3f getPosition() @@ -1484,10 +703,16 @@ public: IrrlichtDevice *irr) { m_smgr = smgr; + m_irr = irr; if(m_meshnode != NULL || m_spritenode != NULL) return; + m_visuals_expired = false; + + if(!m_is_visible || m_is_local_player) + return; + //video::IVideoDriver* driver = smgr->getVideoDriver(); if(m_visual == "sprite"){ @@ -1509,7 +734,61 @@ public: setBillboardTextureMatrix(m_spritenode, txs, tys, 0, 0); } - } else if(m_visual == "cube"){ + } + else if(m_visual == "upright_sprite") + { + scene::SMesh *mesh = new scene::SMesh(); + double dx = BS*m_visual_size.X/2; + double dy = BS*m_visual_size.Y/2; + { // Front + scene::IMeshBuffer *buf = new scene::SMeshBuffer(); + video::SColor c(255,255,255,255); + video::S3DVertex vertices[4] = + { + video::S3DVertex(-dx,-dy,0, 0,0,0, c, 0,1), + video::S3DVertex(dx,-dy,0, 0,0,0, c, 1,1), + video::S3DVertex(dx,dy,0, 0,0,0, c, 1,0), + video::S3DVertex(-dx,dy,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(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_visual == "cube"){ infostream<<"GenericCAO::addToScene(): cube"<addMeshSceneNode(mesh, NULL); @@ -1523,14 +802,27 @@ public: <<"\" not supported"<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(); } - void updateVisuals() + void expireVisuals() { - removeFromScene(); - // We haven't got any IrrlichtDevices but it isn't actually needed - addToScene(m_smgr, m_gamedef->tsrc(), NULL); + m_visuals_expired = true; } void updateLight(u8 light_at_pos) @@ -1557,6 +849,9 @@ public: { 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_spritenode){ m_spritenode->setPosition(pos_translator.vect_show); @@ -1565,6 +860,14 @@ public: void step(float dtime, ClientEnvironment *env) { + v3f lastpos = pos_translator.vect_show; + + if(m_visuals_expired && m_smgr && m_irr){ + m_visuals_expired = false; + removeFromScene(); + addToScene(m_smgr, m_gamedef->tsrc(), m_irr); + } + if(m_physical){ core::aabbox3d box = m_collisionbox; box.MinEdge *= BS; @@ -1594,6 +897,19 @@ public: 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_makes_footstep_sound){ + 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()); + } + } + m_anim_timer += dtime; if(m_anim_timer >= m_anim_framelength){ m_anim_timer -= m_anim_framelength; @@ -1665,35 +981,67 @@ public: { ITextureSource *tsrc = m_gamedef->tsrc(); - if(m_spritenode){ - std::string texturestring = "unknown_block.png"; - if(m_textures.size() >= 1) - texturestring = m_textures[0]; - texturestring += mod; - m_spritenode->setMaterialTexture(0, - tsrc->getTextureRaw(texturestring)); - } - if(m_meshnode){ - for (u32 i = 0; i < 6; ++i) + if(m_spritenode) + { + if(m_visual == "sprite") { std::string texturestring = "unknown_block.png"; - if(m_textures.size() > i) - texturestring = m_textures[i]; + if(m_textures.size() >= 1) + texturestring = m_textures[0]; texturestring += mod; - AtlasPointer ap = tsrc->getTexture(texturestring); + m_spritenode->setMaterialTexture(0, + tsrc->getTextureRaw(texturestring)); + } + } + if(m_meshnode) + { + if(m_visual == "cube") + { + for (u32 i = 0; i < 6; ++i) + { + std::string texturestring = "unknown_block.png"; + if(m_textures.size() > i) + texturestring = m_textures[i]; + 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; + // 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); + // 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); + } + } + else if(m_visual == "upright_sprite") + { + scene::IMesh *mesh = m_meshnode->getMesh(); + { + std::string tname = "unknown_object.png"; + if(m_textures.size() >= 1) + tname = m_textures[0]; + tname += mod; + scene::IMeshBuffer *buf = mesh->getMeshBuffer(0); + buf->getMaterial().setTexture(0, + tsrc->getTextureRaw(tname)); + } + { + std::string tname = "unknown_object.png"; + if(m_textures.size() >= 2) + tname = m_textures[1]; + else if(m_textures.size() >= 1) + tname = m_textures[0]; + tname += mod; + scene::IMeshBuffer *buf = mesh->getMeshBuffer(1); + buf->getMaterial().setTexture(0, + tsrc->getTextureRaw(tname)); + } } } } @@ -1719,7 +1067,9 @@ public: m_textures.push_back(deSerializeString(is)); } m_spritediv = readV2S16(is); - + m_is_visible = readU8(is); + m_makes_footstep_sound = readU8(is); + m_selection_box = m_collisionbox; m_selection_box.MinEdge *= BS; m_selection_box.MaxEdge *= BS; @@ -1727,7 +1077,7 @@ public: m_tx_size.X = 1.0 / m_spritediv.X; m_tx_size.Y = 1.0 / m_spritediv.Y; - updateVisuals(); + expireVisuals(); } else if(cmd == GENERIC_CMD_UPDATE_POSITION) { @@ -1772,7 +1122,6 @@ public: s16 result_hp = readS16(is); m_hp = result_hp; - // TODO: Execute defined fast response } else if(cmd == GENERIC_CMD_UPDATE_ARMOR_GROUPS) { @@ -1797,6 +1146,8 @@ public: toolcap, punchitem, time_from_last_punch); + + dstream<<"Directly did_punch="< ServerActiveObject::m_types; @@ -351,6 +352,7 @@ LuaEntitySAO::LuaEntitySAO(ServerEnvironment *env, v3f pos, m_velocity(0,0,0), m_acceleration(0,0,0), m_yaw(0), + m_properties_sent(true), m_last_sent_yaw(0), m_last_sent_position(0,0,0), m_last_sent_velocity(0,0,0), @@ -434,6 +436,15 @@ ServerActiveObject* LuaEntitySAO::create(ServerEnvironment *env, v3f pos, void LuaEntitySAO::step(float dtime, bool send_recommended) { + if(!m_properties_sent) + { + m_properties_sent = true; + std::string str = getPropertyPacket(); + // create message and add to list + ActiveObjectMessage aom(getId(), true, str); + m_messages_out.push_back(aom); + } + m_last_sent_position_timer += dtime; if(m_prop->physical){ @@ -483,16 +494,10 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) if(m_armor_groups_sent == false){ m_armor_groups_sent = true; - std::ostringstream os(std::ios::binary); - writeU8(os, LUAENTITY_CMD_UPDATE_ARMOR_GROUPS); - writeU16(os, m_armor_groups.size()); - for(ItemGroupList::const_iterator i = m_armor_groups.begin(); - i != m_armor_groups.end(); i++){ - os<first); - writeS16(os, i->second); - } + std::string str = gob_cmd_update_armor_groups( + m_armor_groups); // create message and add to list - ActiveObjectMessage aom(getId(), true, os.str()); + ActiveObjectMessage aom(getId(), true, str); m_messages_out.push_back(aom); } } @@ -500,18 +505,19 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) std::string LuaEntitySAO::getClientInitializationData() { std::ostringstream os(std::ios::binary); - // version - writeU8(os, 1); - // pos + writeU8(os, 0); // version + os<serialize(prop_os); - os<initial_sprite_basepos, + 1, 1.0, false + )); // return result return os.str(); } @@ -574,15 +580,9 @@ int LuaEntitySAO::punch(v3f dir, <<" hp, health now "<hp_max, + m_prop->physical, + m_prop->weight, + m_prop->collisionbox, + m_prop->visual, + m_prop->visual_size, + m_prop->textures, + m_prop->spritediv, + true, // is_visible + false // makes_footstep_sound + ); +} + void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) { m_last_sent_move_precision = m_base_position.getDistanceFrom( @@ -726,28 +736,17 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) float update_interval = m_env->getSendRecommendedInterval(); - std::ostringstream os(std::ios::binary); - // command - writeU8(os, LUAENTITY_CMD_UPDATE_POSITION); - - // do_interpolate - writeU8(os, do_interpolate); - // pos - writeV3F1000(os, m_base_position); - // velocity - writeV3F1000(os, m_velocity); - // acceleration - writeV3F1000(os, m_acceleration); - // yaw - writeF1000(os, m_yaw); - // is_end_position (for interpolation) - writeU8(os, is_movement_end); - // update_interval (for interpolation) - writeF1000(os, update_interval); - + std::string str = gob_cmd_update_position( + m_base_position, + m_velocity, + m_acceleration, + m_yaw, + do_interpolate, + is_movement_end, + update_interval + ); // create message and add to list - ActiveObjectMessage aom(getId(), false, os.str()); - m_messages_out.push_back(aom); + ActiveObjectMessage aom(getId(), false, str); } /* @@ -767,6 +766,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_): m_wield_index(0), m_position_not_sent(false), m_armor_groups_sent(false), + m_properties_sent(true), m_teleported(false), m_inventory_not_sent(false), m_hp_not_sent(false), @@ -827,18 +827,15 @@ bool PlayerSAO::unlimitedTransferDistance() const std::string PlayerSAO::getClientInitializationData() { std::ostringstream os(std::ios::binary); - // version - writeU8(os, 0); - // name - os<getName()); - // pos - writeV3F1000(os, m_player->getPosition()); - // yaw + writeU8(os, 0); // version + os<getName()); // name + writeU8(os, 1); // is_player + writeV3F1000(os, m_player->getPosition() + v3f(0,BS*1,0)); writeF1000(os, m_player->getYaw()); - // dead - writeU8(os, getHP() == 0); - // wielded item - os<getPosition()); - // yaw - writeF1000(os, m_player->getYaw()); + float update_interval = m_env->getSendRecommendedInterval(); + std::string str = gob_cmd_update_position( + m_player->getPosition() + v3f(0,BS*1,0), + v3f(0,0,0), + v3f(0,0,0), + m_player->getYaw(), + true, + false, + update_interval + ); // create message and add to list - ActiveObjectMessage aom(getId(), false, os.str()); + ActiveObjectMessage aom(getId(), false, str); m_messages_out.push_back(aom); } if(m_wielded_item_not_sent) { m_wielded_item_not_sent = false; + // GenericCAO has no special way to show this + } - std::ostringstream os(std::ios::binary); - // command (3 = wielded item) - writeU8(os, 3); - // wielded item - os<getBool("enable_pvp") == false){ - if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER) + if(puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER){ + std::string str = gob_cmd_punched(0, getHP()); + // create message and add to list + ActiveObjectMessage aom(getId(), true, str); + m_messages_out.push_back(aom); return 0; + } } HitParams hitparams = getHitParams(m_armor_groups, toolcap, @@ -974,13 +988,9 @@ int PlayerSAO::punch(v3f dir, if(hitparams.hp != 0) { - std::ostringstream os(std::ios::binary); - // command (1 = punched) - writeU8(os, 1); - // damage - writeS16(os, hitparams.hp); + std::string str = gob_cmd_punched(hitparams.hp, getHP()); // create message and add to list - ActiveObjectMessage aom(getId(), false, os.str()); + ActiveObjectMessage aom(getId(), true, str); m_messages_out.push_back(aom); } @@ -1019,13 +1029,11 @@ void PlayerSAO::setHP(s16 hp) // On death or reincarnation send an active object message if((hp == 0) != (oldhp == 0)) { - std::ostringstream os(std::ios::binary); - // command (2 = update death state) - writeU8(os, 2); - // dead? - writeU8(os, hp == 0); - // create message and add to list - ActiveObjectMessage aom(getId(), false, os.str()); + // Will send new is_visible value based on (getHP()!=0) + m_properties_sent = false; + // Send new HP + std::string str = gob_cmd_punched(0, getHP()); + ActiveObjectMessage aom(getId(), true, str); m_messages_out.push_back(aom); } } @@ -1097,3 +1105,22 @@ void PlayerSAO::createCreativeInventory() scriptapi_get_creative_inventory(m_env->getLua(), this); } +std::string PlayerSAO::getPropertyPacket() +{ + core::array textures; + textures.push_back("player.png"); + textures.push_back("player_back.png"); + return gob_cmd_set_properties( + PLAYER_MAX_HP, + false, + 75, + core::aabbox3d(-1/3.,-1.0,-1/3., 1/3.,1.0,1/3.), + "upright_sprite", + v2f(1, 2), + textures, + v2s16(1,1), + (getHP() != 0), // is_visible + true // makes_footstep_sound + ); +} + diff --git a/src/content_sao.h b/src/content_sao.h index 600499b0..48a5078b 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -41,7 +41,9 @@ public: const std::string &name, const std::string &state); ~LuaEntitySAO(); u8 getType() const - {return ACTIVEOBJECT_TYPE_LUAENTITY;} + { return ACTIVEOBJECT_TYPE_LUAENTITY; } + u8 getSendType() const + { return ACTIVEOBJECT_TYPE_GENERIC; } virtual void addedToEnvironment(); static ServerActiveObject* create(ServerEnvironment *env, v3f pos, const std::string &data); @@ -72,6 +74,7 @@ public: bool select_horiz_by_yawpitch); std::string getName(); private: + std::string getPropertyPacket(); void sendPosition(bool do_interpolate, bool is_movement_end); std::string m_init_name; @@ -84,7 +87,8 @@ private: v3f m_acceleration; float m_yaw; ItemGroupList m_armor_groups; - + + bool m_properties_sent; float m_last_sent_yaw; v3f m_last_sent_position; v3f m_last_sent_velocity; @@ -103,7 +107,9 @@ public: PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_); ~PlayerSAO(); u8 getType() const - {return ACTIVEOBJECT_TYPE_PLAYER;} + { return ACTIVEOBJECT_TYPE_PLAYER; } + u8 getSendType() const + { return ACTIVEOBJECT_TYPE_GENERIC; } std::string getDescription(); /* @@ -174,6 +180,8 @@ public: } private: + std::string getPropertyPacket(); + Player *m_player; u16 m_peer_id; Inventory *m_inventory; @@ -184,6 +192,7 @@ private: bool m_position_not_sent; ItemGroupList m_armor_groups; bool m_armor_groups_sent; + bool m_properties_sent; public: // Some flags used by Server diff --git a/src/genericobject.cpp b/src/genericobject.cpp new file mode 100644 index 00000000..3538f0bf --- /dev/null +++ b/src/genericobject.cpp @@ -0,0 +1,136 @@ +/* +Minetest-c55 +Copyright (C) 2012 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 +(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. + +You should have received a copy of the GNU 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. +*/ + +#include "genericobject.h" +#include "utility.h" +#include + +std::string gob_cmd_set_properties( + s16 hp_max, + bool physical, + float weight, + core::aabbox3d collisionbox, + std::string visual, + v2f visual_size, + core::array textures, + v2s16 spritediv, + bool is_visible, + bool makes_footstep_sound +){ + std::ostringstream os(std::ios::binary); + writeU8(os, GENERIC_CMD_SET_PROPERTIES); + writeS16(os, hp_max); + writeU8(os, physical); + writeF1000(os, weight); + writeV3F1000(os, collisionbox.MinEdge); + writeV3F1000(os, collisionbox.MaxEdge); + os<first); + writeS16(os, i->second); + } + return os.str(); +} + + diff --git a/src/genericobject.h b/src/genericobject.h new file mode 100644 index 00000000..1ab7e26a --- /dev/null +++ b/src/genericobject.h @@ -0,0 +1,71 @@ +/* +Minetest-c55 +Copyright (C) 2012 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 +(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. + +You should have received a copy of the GNU 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. +*/ + +#ifndef GENERICOBJECT_HEADER +#define GENERICOBJECT_HEADER + +#include +#include "irrlichttypes.h" + +#define GENERIC_CMD_SET_PROPERTIES 0 +#define GENERIC_CMD_UPDATE_POSITION 1 +#define GENERIC_CMD_SET_TEXTURE_MOD 2 +#define GENERIC_CMD_SET_SPRITE 3 +#define GENERIC_CMD_PUNCHED 4 +#define GENERIC_CMD_UPDATE_ARMOR_GROUPS 5 + +std::string gob_cmd_set_properties( + s16 hp_max, + bool physical, + float weight, + core::aabbox3d collisionbox, + std::string visual, + v2f visual_size, + core::array textures, + v2s16 spritediv, + bool is_visible, + bool makes_footstep_sound +); + +std::string gob_cmd_update_position( + v3f position, + v3f velocity, + v3f acceleration, + f32 yaw, + bool do_interpolate, + bool is_movement_end, + f32 update_interval +); + +std::string gob_cmd_set_texture_mod(const std::string &mod); + +std::string gob_cmd_set_sprite( + v2s16 p, + u16 num_frames, + f32 framelength, + bool select_horiz_by_yawpitch +); + +std::string gob_cmd_punched(s16 damage, s16 result_hp); + +#include "itemgroup.h" +std::string gob_cmd_update_armor_groups(const ItemGroupList &armor_groups); + +#endif +