diff options
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/content_cao.cpp | 488 | ||||
-rw-r--r-- | src/content_object.h | 3 | ||||
-rw-r--r-- | src/content_sao.cpp | 51 | ||||
-rw-r--r-- | src/content_sao.h | 5 | ||||
-rw-r--r-- | src/server.cpp | 2 | ||||
-rw-r--r-- | src/serverobject.h | 7 |
7 files changed, 532 insertions, 25 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2558be9cb..4e7ac3152 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -153,6 +153,7 @@ configure_file( ) set(common_SRCS + genericobject.cpp voxelalgorithms.cpp sound.cpp quicktune.cpp diff --git a/src/content_cao.cpp b/src/content_cao.cpp index 11c9ad9c6..da4ab6144 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -1349,4 +1349,492 @@ public: // Prototype PlayerCAO proto_PlayerCAO(NULL, NULL); +/* + GenericCAO +*/ + +#include "genericobject.h" + +class GenericCAO : public ClientActiveObject +{ +private: + // Property-ish things + s16 m_hp_max; + bool m_physical; + float m_weight; + core::aabbox3d<f32> m_collisionbox; + std::string m_visual; + v2f m_visual_size; + core::array<std::string> m_textures; + v2s16 m_spritediv; + // + scene::ISceneManager *m_smgr; + core::aabbox3d<f32> 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; + 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: + GenericCAO(IGameDef *gamedef, ClientEnvironment *env): + ClientActiveObject(0, gamedef, env), + // + m_hp_max(1), + m_physical(false), + m_weight(5), + m_collisionbox(-0.5,-0.5,-0.5, 0.5,0.5,0.5), + m_visual("sprite"), + m_visual_size(1,1), + m_spritediv(1,1), + // + 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_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) + { + m_textures.push_back("unknown_object.png"); + if(gamedef == NULL) + ClientActiveObject::registerType(getType(), create); + } + + void initialize(const std::string &data) + { + infostream<<"GenericCAO: Got init data"<<std::endl; + + std::istringstream is(data, std::ios::binary); + // version + u8 version = readU8(is); + // check version + if(version != 1) + return; + // pos + m_position = readV3F1000(is); + // yaw + m_yaw = readF1000(is); + // hp + m_hp = readS16(is); + + pos_translator.init(m_position); + + updateNodePos(); + } + + ~GenericCAO() + { + } + + static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env) + { + return new GenericCAO(gamedef, env); + } + + u8 getType() const + { + return ACTIVEOBJECT_TYPE_GENERIC; + } + core::aabbox3d<f32>* getSelectionBox() + { + return &m_selection_box; + } + v3f getPosition() + { + return pos_translator.vect_show; + } + + void removeFromScene() + { + if(m_meshnode){ + m_meshnode->remove(); + m_meshnode = NULL; + } + if(m_spritenode){ + m_spritenode->remove(); + m_spritenode = NULL; + } + } + + 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_visual == "sprite"){ + infostream<<"GenericCAO::addToScene(): single_sprite"<<std::endl; + m_spritenode = smgr->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_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_visual == "cube"){ + infostream<<"GenericCAO::addToScene(): cube"<<std::endl; + scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS)); + m_meshnode = smgr->addMeshSceneNode(mesh, NULL); + mesh->drop(); + + m_meshnode->setScale(v3f(1)); + // Will be shown when we know the brightness + m_meshnode->setVisible(false); + } else { + infostream<<"GenericCAO::addToScene(): \""<<m_visual + <<"\" not supported"<<std::endl; + } + updateTextures(""); + updateNodePos(); + } + + void updateVisuals() + { + removeFromScene(); + // We haven't got any IrrlichtDevices but it isn't actually needed + addToScene(m_smgr, m_gamedef->tsrc(), 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_physical){ + core::aabbox3d<f32> box = m_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="<<m_id<<" dir="<<dir<<std::endl; + if(fabs(wrapDegrees_180(dir - 0)) <= 45.1) + col += 2; + else if(fabs(wrapDegrees_180(dir - 90)) <= 45.1) + col += 3; + else if(fabs(wrapDegrees_180(dir - 180)) <= 45.1) + col += 0; + else if(fabs(wrapDegrees_180(dir + 90)) <= 45.1) + col += 1; + else + col += 4; + } + } + + // Animation goes downwards + row += m_anim_frame; + + float txs = m_tx_size.X; + float tys = m_tx_size.Y; + setBillboardTextureMatrix(m_spritenode, + txs, tys, col, row); + } + } + + void updateTextures(const std::string &mod) + { + 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) + { + 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; + + // 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<<"GenericCAO: Got message"<<std::endl; + std::istringstream is(data, std::ios::binary); + // command + u8 cmd = readU8(is); + if(cmd == GENERIC_CMD_SET_PROPERTIES) + { + m_hp_max = readS16(is); + m_physical = readU8(is); + m_weight = readF1000(is); + m_collisionbox.MinEdge = readV3F1000(is); + m_collisionbox.MaxEdge = readV3F1000(is); + m_visual = deSerializeString(is); + m_visual_size = readV2F1000(is); + m_textures.clear(); + u32 texture_count = readU16(is); + for(u32 i=0; i<texture_count; i++){ + m_textures.push_back(deSerializeString(is)); + } + m_spritediv = readV2S16(is); + + m_selection_box = m_collisionbox; + m_selection_box.MinEdge *= BS; + m_selection_box.MaxEdge *= BS; + + m_tx_size.X = 1.0 / m_spritediv.X; + m_tx_size.Y = 1.0 / m_spritediv.Y; + + updateVisuals(); + } + else if(cmd == GENERIC_CMD_UPDATE_POSITION) + { + m_position = readV3F1000(is); + m_velocity = readV3F1000(is); + m_acceleration = readV3F1000(is); + m_yaw = readF1000(is); + bool do_interpolate = readU8(is); + bool is_end_position = readU8(is); + float update_interval = readF1000(is); + + if(do_interpolate){ + if(!m_physical) + pos_translator.update(m_position, is_end_position, update_interval); + } else { + pos_translator.init(m_position); + } + updateNodePos(); + } + else if(cmd == GENERIC_CMD_SET_TEXTURE_MOD) + { + std::string mod = deSerializeString(is); + updateTextures(mod); + } + else if(cmd == GENERIC_CMD_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 == GENERIC_CMD_PUNCHED) + { + /*s16 damage =*/ readS16(is); + s16 result_hp = readS16(is); + + m_hp = result_hp; + // TODO: Execute defined fast response + } + else if(cmd == GENERIC_CMD_UPDATE_ARMOR_GROUPS) + { + m_armor_groups.clear(); + int armor_groups_size = readU16(is); + for(int i=0; i<armor_groups_size; i++){ + std::string name = deSerializeString(is); + int rating = readS16(is); + m_armor_groups[name] = rating; + } + } + } + + bool directReportPunch(v3f dir, const ItemStack *punchitem=NULL, + float time_from_last_punch=1000000) + { + assert(punchitem); + const ToolCapabilities *toolcap = + &punchitem->getToolCapabilities(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_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<<"GenericCAO hp="<<m_hp<<"\n"; + os<<"armor={"; + for(ItemGroupList::const_iterator i = m_armor_groups.begin(); + i != m_armor_groups.end(); i++){ + os<<i->first<<"="<<i->second<<", "; + } + os<<"}"; + return os.str(); + } +}; + +// Prototype +GenericCAO proto_GenericCAO(NULL, NULL); + diff --git a/src/content_object.h b/src/content_object.h index 0b85e3cf1..aa73d107c 100644 --- a/src/content_object.h +++ b/src/content_object.h @@ -32,5 +32,8 @@ with this program; if not, write to the Free Software Foundation, Inc., // Special type, not stored as a static object #define ACTIVEOBJECT_TYPE_PLAYER 100 +// Special type, only exists as CAO +#define ACTIVEOBJECT_TYPE_GENERIC 101 + #endif diff --git a/src/content_sao.cpp b/src/content_sao.cpp index d01b023de..fb8b23fbf 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -605,17 +605,6 @@ void LuaEntitySAO::rightClick(ServerActiveObject *clicker) scriptapi_luaentity_rightclick(L, m_id, clicker); } -void LuaEntitySAO::setHP(s16 hp) -{ - if(hp < 0) hp = 0; - m_hp = hp; -} - -s16 LuaEntitySAO::getHP() const -{ - return m_hp; -} - void LuaEntitySAO::setPos(v3f pos) { m_base_position = pos; @@ -645,6 +634,23 @@ std::string LuaEntitySAO::getDescription() return os.str(); } +void LuaEntitySAO::setHP(s16 hp) +{ + if(hp < 0) hp = 0; + m_hp = hp; +} + +s16 LuaEntitySAO::getHP() const +{ + return m_hp; +} + +void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups) +{ + m_armor_groups = armor_groups; + m_armor_groups_sent = false; +} + void LuaEntitySAO::setVelocity(v3f velocity) { m_velocity = velocity; @@ -708,12 +714,6 @@ std::string LuaEntitySAO::getName() return m_init_name; } -void LuaEntitySAO::setArmorGroups(const ItemGroupList &armor_groups) -{ - m_armor_groups = armor_groups; - m_armor_groups_sent = false; -} - void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) { m_last_sent_move_precision = m_base_position.getDistanceFrom( @@ -766,6 +766,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_): m_time_from_last_punch(0), m_wield_index(0), m_position_not_sent(false), + m_armor_groups_sent(false), m_teleported(false), m_inventory_not_sent(false), m_hp_not_sent(false), @@ -775,6 +776,8 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_): assert(m_peer_id != 0); setBasePosition(m_player->getPosition()); m_inventory = &m_player->inventory; + m_armor_groups["choppy"] = 2; + m_armor_groups["fleshy"] = 3; } PlayerSAO::~PlayerSAO() @@ -960,12 +963,8 @@ int PlayerSAO::punch(v3f dir, return 0; } - // "Material" groups of the player - ItemGroupList groups; - groups["choppy"] = 2; - groups["fleshy"] = 3; - - HitParams hitparams = getHitParams(groups, toolcap, time_from_last_punch); + HitParams hitparams = getHitParams(m_armor_groups, toolcap, + time_from_last_punch); actionstream<<"Player "<<m_player->getName()<<" punched by " <<puncher->getDescription()<<", damage "<<hitparams.hp @@ -1031,6 +1030,12 @@ void PlayerSAO::setHP(s16 hp) } } +void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups) +{ + m_armor_groups = armor_groups; + m_armor_groups_sent = false; +} + Inventory* PlayerSAO::getInventory() { return m_inventory; diff --git a/src/content_sao.h b/src/content_sao.h index 9ceb6ed6a..600499b0d 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -59,6 +59,7 @@ public: std::string getDescription(); void setHP(s16 hp); s16 getHP() const; + void setArmorGroups(const ItemGroupList &armor_groups); /* LuaEntitySAO-specific */ void setVelocity(v3f velocity); v3f getVelocity(); @@ -70,7 +71,6 @@ public: void setSprite(v2s16 p, int num_frames, float framelength, bool select_horiz_by_yawpitch); std::string getName(); - void setArmorGroups(const ItemGroupList &armor_groups); private: void sendPosition(bool do_interpolate, bool is_movement_end); @@ -132,6 +132,7 @@ public: void rightClick(ServerActiveObject *clicker); s16 getHP() const; void setHP(s16 hp); + void setArmorGroups(const ItemGroupList &armor_groups); /* Inventory interface @@ -181,6 +182,8 @@ private: float m_time_from_last_punch; int m_wield_index; bool m_position_not_sent; + ItemGroupList m_armor_groups; + bool m_armor_groups_sent; public: // Some flags used by Server diff --git a/src/server.cpp b/src/server.cpp index 8ad0d0869..4a6165f30 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1515,7 +1515,7 @@ void Server::AsyncRunStep() infostream<<"WARNING: "<<__FUNCTION_NAME <<": NULL object"<<std::endl; else - type = obj->getType(); + type = obj->getSendType(); // Add to data buffer for sending writeU16((u8*)buf, id); diff --git a/src/serverobject.h b/src/serverobject.h index 8719267d7..110f67f5b 100644 --- a/src/serverobject.h +++ b/src/serverobject.h @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "activeobject.h" #include "utility.h" #include "inventorymanager.h" +#include "itemgroup.h" /* @@ -56,6 +57,9 @@ public: ServerActiveObject(ServerEnvironment *env, v3f pos); virtual ~ServerActiveObject(); + virtual u8 getSendType() const + { return getType(); } + // Called after id has been set and has been inserted in environment virtual void addedToEnvironment(){}; // Called before removing from environment @@ -146,6 +150,9 @@ public: virtual s16 getHP() const { return 0; } + virtual void setArmorGroups(const ItemGroupList &armor_groups) + {} + // Inventory and wielded item virtual Inventory* getInventory() { return NULL; } |