diff --git a/src/client.cpp b/src/client.cpp index fee21994..a165627e 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -205,7 +205,7 @@ Client::Client( device->getSceneManager()->getRootSceneNode(), device->getSceneManager(), 666), device->getSceneManager(), - tsrc, this + tsrc, this, device ), m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this), m_device(device), @@ -1010,6 +1010,8 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) } else if(command == TOCLIENT_PLAYERINFO) { + infostream<<"Client received DEPRECATED TOCLIENT_PLAYERINFO"<peer_id); } } //envlock +#endif } else if(command == TOCLIENT_SECTORMETA) { diff --git a/src/clientobject.cpp b/src/clientobject.cpp index 7dec1903..93f3b1cc 100644 --- a/src/clientobject.cpp +++ b/src/clientobject.cpp @@ -26,9 +26,11 @@ with this program; if not, write to the Free Software Foundation, Inc., ClientActiveObject */ -ClientActiveObject::ClientActiveObject(u16 id, IGameDef *gamedef): +ClientActiveObject::ClientActiveObject(u16 id, IGameDef *gamedef, + ClientEnvironment *env): ActiveObject(id), - m_gamedef(gamedef) + m_gamedef(gamedef), + m_env(env) { } @@ -37,7 +39,8 @@ ClientActiveObject::~ClientActiveObject() removeFromScene(); } -ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef) +ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef, + ClientEnvironment *env) { // Find factory function core::map::Node *n; @@ -51,7 +54,7 @@ ClientActiveObject* ClientActiveObject::create(u8 type, IGameDef *gamedef) } Factory f = n->getValue(); - ClientActiveObject *object = (*f)(gamedef); + ClientActiveObject *object = (*f)(gamedef, env); return object; } diff --git a/src/clientobject.h b/src/clientobject.h index 0b3d8623..2e1b850c 100644 --- a/src/clientobject.h +++ b/src/clientobject.h @@ -42,10 +42,11 @@ class IGameDef; class ClientActiveObject : public ActiveObject { public: - ClientActiveObject(u16 id, IGameDef *gamedef); + ClientActiveObject(u16 id, IGameDef *gamedef, ClientEnvironment *env); virtual ~ClientActiveObject(); - virtual void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc){} + virtual void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, + IrrlichtDevice *irr){} virtual void removeFromScene(){} // 0 <= light_at_pos <= LIGHT_SUN virtual void updateLight(u8 light_at_pos){} @@ -70,7 +71,8 @@ public: virtual void initialize(const std::string &data){} // Create a certain type of ClientActiveObject - static ClientActiveObject* create(u8 type, IGameDef *gamedef); + static ClientActiveObject* create(u8 type, IGameDef *gamedef, + ClientEnvironment *env); // If returns true, punch will not be sent to the server virtual bool directReportPunch(const std::string &toolname, v3f dir) @@ -78,9 +80,10 @@ public: protected: // Used for creating objects based on type - typedef ClientActiveObject* (*Factory)(IGameDef *gamedef); + typedef ClientActiveObject* (*Factory)(IGameDef *gamedef, ClientEnvironment *env); static void registerType(u16 type, Factory f); IGameDef *m_gamedef; + ClientEnvironment *m_env; private: // Used for creating objects based on type static core::map m_types; diff --git a/src/content_cao.cpp b/src/content_cao.cpp index ba8739df..011a3f40 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -22,20 +22,393 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "environment.h" #include "settings.h" #include +#include #include "serialization.h" // For decompressZlib #include "gamedef.h" +#include "clientobject.h" +#include "content_object.h" +#include "utility.h" // For IntervalLimiter +class Settings; +#include "MyBillboardSceneNode.h" core::map ClientActiveObject::m_types; +/* + SmoothTranslator +*/ + +struct SmoothTranslator +{ + v3f vect_old; + v3f vect_show; + v3f vect_aim; + f32 anim_counter; + f32 anim_time; + f32 anim_time_counter; + bool aim_is_end; + + SmoothTranslator(): + vect_old(0,0,0), + vect_show(0,0,0), + vect_aim(0,0,0), + anim_counter(0), + anim_time(0), + anim_time_counter(0), + aim_is_end(true) + {} + + void init(v3f vect) + { + vect_old = vect; + vect_show = vect; + vect_aim = vect; + anim_counter = 0; + anim_time = 0; + anim_time_counter = 0; + aim_is_end = true; + } + + void sharpen() + { + init(vect_show); + } + + void update(v3f vect_new, bool is_end_position=false, float update_interval=-1) + { + aim_is_end = is_end_position; + vect_old = vect_show; + vect_aim = vect_new; + if(update_interval > 0){ + anim_time = update_interval; + } else { + if(anim_time < 0.001 || anim_time > 1.0) + anim_time = anim_time_counter; + else + anim_time = anim_time * 0.9 + anim_time_counter * 0.1; + } + anim_time_counter = 0; + anim_counter = 0; + } + + void translate(f32 dtime) + { + anim_time_counter = anim_time_counter + dtime; + anim_counter = anim_counter + dtime; + v3f vect_move = vect_aim - vect_old; + f32 moveratio = 1.0; + if(anim_time > 0.001) + moveratio = anim_time_counter / anim_time; + // Move a bit less than should, to avoid oscillation + moveratio = moveratio * 0.8; + float move_end = 1.5; + if(aim_is_end) + move_end = 1.0; + if(moveratio > move_end) + moveratio = move_end; + vect_show = vect_old + vect_move * moveratio; + } + + bool is_moving() + { + return ((anim_time_counter / anim_time) < 1.4); + } +}; + + +/* + TestCAO +*/ + +class TestCAO : public ClientActiveObject +{ +public: + TestCAO(IGameDef *gamedef, ClientEnvironment *env); + virtual ~TestCAO(); + + u8 getType() const + { + return ACTIVEOBJECT_TYPE_TEST; + } + + static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env); + + void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, + IrrlichtDevice *irr); + void removeFromScene(); + void updateLight(u8 light_at_pos); + v3s16 getLightPosition(); + void updateNodePos(); + + void step(float dtime, ClientEnvironment *env); + + void processMessage(const std::string &data); + +private: + scene::IMeshSceneNode *m_node; + v3f m_position; +}; + +/* + ItemCAO +*/ + +class ItemCAO : public ClientActiveObject +{ +public: + ItemCAO(IGameDef *gamedef, ClientEnvironment *env); + virtual ~ItemCAO(); + + u8 getType() const + { + return ACTIVEOBJECT_TYPE_ITEM; + } + + static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env); + + void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, + IrrlichtDevice *irr); + void removeFromScene(); + void updateLight(u8 light_at_pos); + v3s16 getLightPosition(); + void updateNodePos(); + + void step(float dtime, ClientEnvironment *env); + + void processMessage(const std::string &data); + + void initialize(const std::string &data); + + core::aabbox3d* getSelectionBox() + {return &m_selection_box;} + v3f getPosition() + {return m_position;} + +private: + core::aabbox3d m_selection_box; + scene::IMeshSceneNode *m_node; + v3f m_position; + std::string m_inventorystring; +}; + +/* + RatCAO +*/ + +class RatCAO : public ClientActiveObject +{ +public: + RatCAO(IGameDef *gamedef, ClientEnvironment *env); + virtual ~RatCAO(); + + u8 getType() const + { + return ACTIVEOBJECT_TYPE_RAT; + } + + static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env); + + void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, + IrrlichtDevice *irr); + void removeFromScene(); + void updateLight(u8 light_at_pos); + v3s16 getLightPosition(); + void updateNodePos(); + + void step(float dtime, ClientEnvironment *env); + + void processMessage(const std::string &data); + + void initialize(const std::string &data); + + core::aabbox3d* getSelectionBox() + {return &m_selection_box;} + v3f getPosition() + {return pos_translator.vect_show;} + //{return m_position;} + +private: + core::aabbox3d m_selection_box; + scene::IMeshSceneNode *m_node; + v3f m_position; + float m_yaw; + SmoothTranslator pos_translator; +}; + +/* + Oerkki1CAO +*/ + +class Oerkki1CAO : public ClientActiveObject +{ +public: + Oerkki1CAO(IGameDef *gamedef, ClientEnvironment *env); + virtual ~Oerkki1CAO(); + + u8 getType() const + { + return ACTIVEOBJECT_TYPE_OERKKI1; + } + + static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env); + + void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, + IrrlichtDevice *irr); + void removeFromScene(); + void updateLight(u8 light_at_pos); + v3s16 getLightPosition(); + void updateNodePos(); + + void step(float dtime, ClientEnvironment *env); + + void processMessage(const std::string &data); + + void initialize(const std::string &data); + + core::aabbox3d* getSelectionBox() + {return &m_selection_box;} + v3f getPosition() + {return pos_translator.vect_show;} + //{return m_position;} + + // If returns true, punch will not be sent to the server + bool directReportPunch(const std::string &toolname, v3f dir); + +private: + IntervalLimiter m_attack_interval; + core::aabbox3d m_selection_box; + scene::IMeshSceneNode *m_node; + v3f m_position; + float m_yaw; + SmoothTranslator pos_translator; + float m_damage_visual_timer; + bool m_damage_texture_enabled; +}; + +/* + FireflyCAO +*/ + +class FireflyCAO : public ClientActiveObject +{ +public: + FireflyCAO(IGameDef *gamedef, ClientEnvironment *env); + virtual ~FireflyCAO(); + + u8 getType() const + { + return ACTIVEOBJECT_TYPE_FIREFLY; + } + + static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env); + + void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, + IrrlichtDevice *irr); + void removeFromScene(); + void updateLight(u8 light_at_pos); + v3s16 getLightPosition(); + void updateNodePos(); + + void step(float dtime, ClientEnvironment *env); + + void processMessage(const std::string &data); + + void initialize(const std::string &data); + + core::aabbox3d* getSelectionBox() + {return &m_selection_box;} + v3f getPosition() + {return m_position;} + +private: + core::aabbox3d m_selection_box; + scene::IMeshSceneNode *m_node; + v3f m_position; + float m_yaw; + SmoothTranslator pos_translator; +}; + +/* + MobV2CAO +*/ + +class MobV2CAO : public ClientActiveObject +{ +public: + MobV2CAO(IGameDef *gamedef, ClientEnvironment *env); + virtual ~MobV2CAO(); + + u8 getType() const + { + return ACTIVEOBJECT_TYPE_MOBV2; + } + + static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env); + + void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, + IrrlichtDevice *irr); + void removeFromScene(); + void updateLight(u8 light_at_pos); + v3s16 getLightPosition(); + void updateNodePos(); + + void step(float dtime, ClientEnvironment *env); + + void processMessage(const std::string &data); + + void initialize(const std::string &data); + + core::aabbox3d* getSelectionBox() + {return &m_selection_box;} + v3f getPosition() + {return pos_translator.vect_show;} + //{return m_position;} + bool doShowSelectionBox(){return false;} + + // If returns true, punch will not be sent to the server + bool directReportPunch(const std::string &toolname, v3f dir); + +private: + void setLooks(const std::string &looks); + + IntervalLimiter m_attack_interval; + core::aabbox3d m_selection_box; + scene::MyBillboardSceneNode *m_node; + v3f m_position; + std::string m_texture_name; + float m_yaw; + SmoothTranslator pos_translator; + bool m_walking; + float m_walking_unset_timer; + float m_walk_timer; + int m_walk_frame; + float m_damage_visual_timer; + u8 m_last_light; + bool m_shooting; + float m_shooting_unset_timer; + v2f m_sprite_size; + float m_sprite_y; + bool m_bright_shooting; + std::string m_sprite_type; + int m_simple_anim_frames; + float m_simple_anim_frametime; + bool m_lock_full_brightness; + int m_player_hit_damage; + float m_player_hit_distance; + float m_player_hit_interval; + float m_player_hit_timer; + + Settings *m_properties; +}; + /* TestCAO */ // Prototype -TestCAO proto_TestCAO(NULL); +TestCAO proto_TestCAO(NULL, NULL); -TestCAO::TestCAO(IGameDef *gamedef): - ClientActiveObject(0, gamedef), +TestCAO::TestCAO(IGameDef *gamedef, ClientEnvironment *env): + ClientActiveObject(0, gamedef, env), m_node(NULL), m_position(v3f(0,10*BS,0)) { @@ -46,12 +419,13 @@ TestCAO::~TestCAO() { } -ClientActiveObject* TestCAO::create(IGameDef *gamedef) +ClientActiveObject* TestCAO::create(IGameDef *gamedef, ClientEnvironment *env) { - return new TestCAO(gamedef); + return new TestCAO(gamedef, env); } -void TestCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc) +void TestCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, + IrrlichtDevice *irr) { if(m_node != NULL) return; @@ -147,10 +521,10 @@ void TestCAO::processMessage(const std::string &data) #include "inventory.h" // Prototype -ItemCAO proto_ItemCAO(NULL); +ItemCAO proto_ItemCAO(NULL, NULL); -ItemCAO::ItemCAO(IGameDef *gamedef): - ClientActiveObject(0, gamedef), +ItemCAO::ItemCAO(IGameDef *gamedef, ClientEnvironment *env): + ClientActiveObject(0, gamedef, env), m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.), m_node(NULL), m_position(v3f(0,10*BS,0)) @@ -162,12 +536,13 @@ ItemCAO::~ItemCAO() { } -ClientActiveObject* ItemCAO::create(IGameDef *gamedef) +ClientActiveObject* ItemCAO::create(IGameDef *gamedef, ClientEnvironment *env) { - return new ItemCAO(gamedef); + return new ItemCAO(gamedef, env); } -void ItemCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc) +void ItemCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, + IrrlichtDevice *irr) { if(m_node != NULL) return; @@ -288,7 +663,7 @@ void ItemCAO::step(float dtime, ClientEnvironment *env) void ItemCAO::processMessage(const std::string &data) { - infostream<<"ItemCAO: Got message"< m_selection_box; @@ -1291,8 +1670,8 @@ private: float m_anim_timer; public: - CLuaEntityCAO(IGameDef *gamedef): - LuaEntityCAO(gamedef), + LuaEntityCAO(IGameDef *gamedef, ClientEnvironment *env): + ClientActiveObject(0, gamedef, env), m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.), m_meshnode(NULL), m_spritenode(NULL), @@ -1309,12 +1688,13 @@ public: m_anim_framelength(0.2), m_anim_timer(0) { - ClientActiveObject::registerType(getType(), create); + if(gamedef == NULL) + ClientActiveObject::registerType(getType(), create); } void initialize(const std::string &data) { - infostream<<"CLuaEntityCAO: Got init data"<getVideoDriver(); if(m_prop->visual == "sprite"){ - infostream<<"CLuaEntityCAO::addToScene(): single_sprite"<getRootSceneNode(), smgr, -1, v3f(0,0,0), v2f(1,1)); m_spritenode->setMaterialTexture(0, @@ -1398,7 +1779,7 @@ public: m_spritenode->setTCoords(3, v2f(txs*0, tys*1)); } } else if(m_prop->visual == "cube"){ - infostream<<"CLuaEntityCAO::addToScene(): cube"<setVisible(false); } else { - infostream<<"CLuaEntityCAO::addToScene(): \""<visual + infostream<<"LuaEntityCAO::addToScene(): \""<visual <<"\" not supported"< 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; + +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) + { + 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; + + updateNodePos(); + } + + ~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; + 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().setTexture(0, tsrc->getTextureRaw("player.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; + // 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().setTexture(0, tsrc->getTextureRaw("player_back.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_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)); + + } + + void removeFromScene() + { + if(m_node == NULL) + return; + + m_node->remove(); + m_node = NULL; + } + + void updateLight(u8 light_at_pos) + { + if(m_node == NULL) + return; + + if(light_at_pos <= 2) + { + m_node->setVisible(false); + return; + } + + m_node->setVisible(true); + + u8 li = decode_light(light_at_pos); + video::SColor color(255,li,li,li); + setMeshVerticesColor(m_node->getMesh(), color); + } + + v3s16 getLightPosition() + { + return floatToInt(m_position+v3f(0,BS*1.5,0), BS); + } + + 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) + { + pos_translator.translate(dtime); + updateNodePos(); + } + + void processMessage(const std::string &data) + { + //infostream<<"PlayerCAO: Got message"< 0){ - anim_time = update_interval; - } else { - if(anim_time < 0.001 || anim_time > 1.0) - anim_time = anim_time_counter; - else - anim_time = anim_time * 0.9 + anim_time_counter * 0.1; - } - anim_time_counter = 0; - anim_counter = 0; - } - - void translate(f32 dtime) - { - anim_time_counter = anim_time_counter + dtime; - anim_counter = anim_counter + dtime; - v3f vect_move = vect_aim - vect_old; - f32 moveratio = 1.0; - if(anim_time > 0.001) - moveratio = anim_time_counter / anim_time; - // Move a bit less than should, to avoid oscillation - moveratio = moveratio * 0.8; - float move_end = 1.5; - if(aim_is_end) - move_end = 1.0; - if(moveratio > move_end) - moveratio = move_end; - vect_show = vect_old + vect_move * moveratio; - } - - bool is_moving() - { - return ((anim_time_counter / anim_time) < 1.4); - } -}; - - -/* - TestCAO -*/ - -class TestCAO : public ClientActiveObject -{ -public: - TestCAO(IGameDef *gamedef); - virtual ~TestCAO(); - - u8 getType() const - { - return ACTIVEOBJECT_TYPE_TEST; - } - - static ClientActiveObject* create(IGameDef *gamedef); - - void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc); - void removeFromScene(); - void updateLight(u8 light_at_pos); - v3s16 getLightPosition(); - void updateNodePos(); - - void step(float dtime, ClientEnvironment *env); - - void processMessage(const std::string &data); - -private: - scene::IMeshSceneNode *m_node; - v3f m_position; -}; - -/* - ItemCAO -*/ - -class ItemCAO : public ClientActiveObject -{ -public: - ItemCAO(IGameDef *gamedef); - virtual ~ItemCAO(); - - u8 getType() const - { - return ACTIVEOBJECT_TYPE_ITEM; - } - - static ClientActiveObject* create(IGameDef *gamedef); - - void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc); - void removeFromScene(); - void updateLight(u8 light_at_pos); - v3s16 getLightPosition(); - void updateNodePos(); - - void step(float dtime, ClientEnvironment *env); - - void processMessage(const std::string &data); - - void initialize(const std::string &data); - - core::aabbox3d* getSelectionBox() - {return &m_selection_box;} - v3f getPosition() - {return m_position;} - -private: - core::aabbox3d m_selection_box; - scene::IMeshSceneNode *m_node; - v3f m_position; - std::string m_inventorystring; -}; - -/* - RatCAO -*/ - -class RatCAO : public ClientActiveObject -{ -public: - RatCAO(IGameDef *gamedef); - virtual ~RatCAO(); - - u8 getType() const - { - return ACTIVEOBJECT_TYPE_RAT; - } - - static ClientActiveObject* create(IGameDef *gamedef); - - void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc); - void removeFromScene(); - void updateLight(u8 light_at_pos); - v3s16 getLightPosition(); - void updateNodePos(); - - void step(float dtime, ClientEnvironment *env); - - void processMessage(const std::string &data); - - void initialize(const std::string &data); - - core::aabbox3d* getSelectionBox() - {return &m_selection_box;} - v3f getPosition() - {return pos_translator.vect_show;} - //{return m_position;} - -private: - core::aabbox3d m_selection_box; - scene::IMeshSceneNode *m_node; - v3f m_position; - float m_yaw; - SmoothTranslator pos_translator; -}; - -/* - Oerkki1CAO -*/ - -class Oerkki1CAO : public ClientActiveObject -{ -public: - Oerkki1CAO(IGameDef *gamedef); - virtual ~Oerkki1CAO(); - - u8 getType() const - { - return ACTIVEOBJECT_TYPE_OERKKI1; - } - - static ClientActiveObject* create(IGameDef *gamedef); - - void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc); - void removeFromScene(); - void updateLight(u8 light_at_pos); - v3s16 getLightPosition(); - void updateNodePos(); - - void step(float dtime, ClientEnvironment *env); - - void processMessage(const std::string &data); - - void initialize(const std::string &data); - - core::aabbox3d* getSelectionBox() - {return &m_selection_box;} - v3f getPosition() - {return pos_translator.vect_show;} - //{return m_position;} - - // If returns true, punch will not be sent to the server - bool directReportPunch(const std::string &toolname, v3f dir); - -private: - IntervalLimiter m_attack_interval; - core::aabbox3d m_selection_box; - scene::IMeshSceneNode *m_node; - v3f m_position; - float m_yaw; - SmoothTranslator pos_translator; - float m_damage_visual_timer; - bool m_damage_texture_enabled; -}; - -/* - FireflyCAO -*/ - -class FireflyCAO : public ClientActiveObject -{ -public: - FireflyCAO(IGameDef *gamedef); - virtual ~FireflyCAO(); - - u8 getType() const - { - return ACTIVEOBJECT_TYPE_FIREFLY; - } - - static ClientActiveObject* create(IGameDef *gamedef); - - void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc); - void removeFromScene(); - void updateLight(u8 light_at_pos); - v3s16 getLightPosition(); - void updateNodePos(); - - void step(float dtime, ClientEnvironment *env); - - void processMessage(const std::string &data); - - void initialize(const std::string &data); - - core::aabbox3d* getSelectionBox() - {return &m_selection_box;} - v3f getPosition() - {return m_position;} - -private: - core::aabbox3d m_selection_box; - scene::IMeshSceneNode *m_node; - v3f m_position; - float m_yaw; - SmoothTranslator pos_translator; -}; - -/* - MobV2CAO -*/ - -class MobV2CAO : public ClientActiveObject -{ -public: - MobV2CAO(IGameDef *gamedef); - virtual ~MobV2CAO(); - - u8 getType() const - { - return ACTIVEOBJECT_TYPE_MOBV2; - } - - static ClientActiveObject* create(IGameDef *gamedef); - - void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc); - void removeFromScene(); - void updateLight(u8 light_at_pos); - v3s16 getLightPosition(); - void updateNodePos(); - - void step(float dtime, ClientEnvironment *env); - - void processMessage(const std::string &data); - - void initialize(const std::string &data); - - core::aabbox3d* getSelectionBox() - {return &m_selection_box;} - v3f getPosition() - {return pos_translator.vect_show;} - //{return m_position;} - bool doShowSelectionBox(){return false;} - - // If returns true, punch will not be sent to the server - bool directReportPunch(const std::string &toolname, v3f dir); - -private: - void setLooks(const std::string &looks); - - IntervalLimiter m_attack_interval; - core::aabbox3d m_selection_box; - scene::MyBillboardSceneNode *m_node; - v3f m_position; - std::string m_texture_name; - float m_yaw; - SmoothTranslator pos_translator; - bool m_walking; - float m_walking_unset_timer; - float m_walk_timer; - int m_walk_frame; - float m_damage_visual_timer; - u8 m_last_light; - bool m_shooting; - float m_shooting_unset_timer; - v2f m_sprite_size; - float m_sprite_y; - bool m_bright_shooting; - std::string m_sprite_type; - int m_simple_anim_frames; - float m_simple_anim_frametime; - bool m_lock_full_brightness; - int m_player_hit_damage; - float m_player_hit_distance; - float m_player_hit_interval; - float m_player_hit_timer; - - Settings *m_properties; -}; - -/* - LuaEntityCAO -*/ - -class LuaEntityCAO : public ClientActiveObject -{ -public: - LuaEntityCAO(IGameDef *gamedef): - ClientActiveObject(0, gamedef) - {} - virtual ~LuaEntityCAO(){} - virtual u8 getType() const=0; - virtual void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc)=0; - virtual void removeFromScene()=0; - virtual void updateLight(u8 light_at_pos)=0; - virtual v3s16 getLightPosition()=0; - virtual void updateNodePos()=0; - virtual void step(float dtime, ClientEnvironment *env)=0; - virtual void processMessage(const std::string &data)=0; - virtual void initialize(const std::string &data)=0; - virtual core::aabbox3d* getSelectionBox()=0; - virtual v3f getPosition()=0; -private: -}; - - #endif diff --git a/src/content_object.h b/src/content_object.h index af863614..0b85e3cf 100644 --- a/src/content_object.h +++ b/src/content_object.h @@ -29,7 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define ACTIVEOBJECT_TYPE_LUAENTITY 7 -// Special type, not stored in active object lists +// Special type, not stored as a static object #define ACTIVEOBJECT_TYPE_PLAYER 100 #endif diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 414d63f2..a4c9c59f 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -1799,4 +1799,96 @@ void LuaEntitySAO::sendPosition(bool do_interpolate, bool is_movement_end) m_messages_out.push_back(aom); } +/* + PlayerSAO +*/ + +// Prototype +PlayerSAO proto_PlayerSAO(NULL, v3f(0,0,0), NULL); + +PlayerSAO::PlayerSAO(ServerEnvironment *env, v3f pos, + ServerRemotePlayer *player): + ServerActiveObject(env, pos), + m_player(player), + m_position_updated(true) +{ + if(m_player) + m_player->setSAO(this); +} + +PlayerSAO::~PlayerSAO() +{ + if(m_player) + m_player->setSAO(NULL); +} + +void PlayerSAO::step(float dtime, bool send_recommended) +{ + if(!m_player) + return; + + if(send_recommended == false) + return; + + if(m_position_updated) + { + m_position_updated = false; + + std::ostringstream os(std::ios::binary); + // command (0 = update position) + writeU8(os, 0); + // pos + writeV3F1000(os, m_player->getPosition()); + // yaw + writeF1000(os, m_player->getYaw()); + // create message and add to list + ActiveObjectMessage aom(getId(), false, os.str()); + m_messages_out.push_back(aom); + } +} + +std::string PlayerSAO::getClientInitializationData() +{ + if(!m_player) + return ""; + + std::ostringstream os(std::ios::binary); + // version + writeU8(os, 0); + // name + os<getName()); + // pos + writeV3F1000(os, m_player->getPosition()); + // yaw + writeF1000(os, m_player->getYaw()); + return os.str(); +} + +std::string PlayerSAO::getStaticData() +{ + assert(0); + return ""; +} + +void PlayerSAO::punch(ServerActiveObject *puncher) +{ + infostream<<"TODO: PlayerSAO::punch()"<getName():"(NULL)")<<"\""<getBasePosition(); - std::string staticdata = object->getStaticData(); - StaticObject s_obj(object->getType(), objectpos, staticdata); - // Add to the block where the object is located in - v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS)); - MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos); - if(block) - { - block->m_static_objects.m_active.insert(object->getId(), s_obj); - object->m_static_exists = true; - object->m_static_block = blockpos; - - if(set_changed) - block->raiseModified(MOD_STATE_WRITE_NEEDED, - "addActiveObjectRaw"); - } - else{ - errorstream<<"ServerEnvironment::addActiveObjectRaw(): " - <<"could not find block for storing id="<getId() - <<" statically"<addedToEnvironment(); + + // Add static data to block + if(object->isStaticAllowed()) + { + // Add static object to active static list of the block + v3f objectpos = object->getBasePosition(); + std::string staticdata = object->getStaticData(); + StaticObject s_obj(object->getType(), objectpos, staticdata); + // Add to the block where the object is located in + v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS)); + MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos); + if(block) + { + block->m_static_objects.m_active.insert(object->getId(), s_obj); + object->m_static_exists = true; + object->m_static_block = blockpos; + if(set_changed) + block->raiseModified(MOD_STATE_WRITE_NEEDED, + "addActiveObjectRaw"); + } + else{ + errorstream<<"ServerEnvironment::addActiveObjectRaw(): " + <<"could not find block for storing id="<getId() + <<" statically"<getId(); } @@ -1547,18 +1553,14 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete) i.atEnd()==false; i++) { ServerActiveObject* obj = i.getNode()->getValue(); - - // This shouldn't happen but check it - if(obj == NULL) - { - errorstream<<"NULL object found in ServerEnvironment" - <isStaticAllowed()) continue; - } // If pending deactivation, let removeRemovedObjects() do it - if(obj->m_pending_deactivation) + if(!force_delete && obj->m_pending_deactivation) continue; u16 id = i.getNode()->getKey(); @@ -1568,7 +1570,7 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete) v3s16 blockpos_o = getNodeBlockPos(floatToInt(objectpos, BS)); // If block is active, don't remove - if(m_active_blocks.contains(blockpos_o)) + if(!force_delete && m_active_blocks.contains(blockpos_o)) continue; verbosestream<<"ServerEnvironment::deactivateFarObjects(): " @@ -1582,97 +1584,102 @@ void ServerEnvironment::deactivateFarObjects(bool force_delete) Update the static data */ - // Create new static object - std::string staticdata_new = obj->getStaticData(); - StaticObject s_obj(obj->getType(), objectpos, staticdata_new); - - bool stays_in_same_block = false; - bool data_changed = true; - - if(obj->m_static_exists){ - if(obj->m_static_block == blockpos_o) - stays_in_same_block = true; - - MapBlock *block = m_map->emergeBlock(obj->m_static_block, false); - - core::map::Node *n = - block->m_static_objects.m_active.find(id); - if(n){ - StaticObject static_old = n->getValue(); - - float save_movem = obj->getMinimumSavedMovement(); - - if(static_old.data == staticdata_new && - (static_old.pos - objectpos).getLength() < save_movem) - data_changed = false; - } else { - errorstream<<"ServerEnvironment::deactivateFarObjects(): " - <<"id="<m_static_block)<m_static_exists) + if(obj->isStaticAllowed()) { - MapBlock *block = m_map->emergeBlock(obj->m_static_block, false); + // Create new static object + std::string staticdata_new = obj->getStaticData(); + StaticObject s_obj(obj->getType(), objectpos, staticdata_new); + + bool stays_in_same_block = false; + bool data_changed = true; + + if(obj->m_static_exists){ + if(obj->m_static_block == blockpos_o) + stays_in_same_block = true; + + MapBlock *block = m_map->emergeBlock(obj->m_static_block, false); + + core::map::Node *n = + block->m_static_objects.m_active.find(id); + if(n){ + StaticObject static_old = n->getValue(); + + float save_movem = obj->getMinimumSavedMovement(); + + if(static_old.data == staticdata_new && + (static_old.pos - objectpos).getLength() < save_movem) + data_changed = false; + } else { + errorstream<<"ServerEnvironment::deactivateFarObjects(): " + <<"id="<m_static_block)<m_static_exists) + { + MapBlock *block = m_map->emergeBlock(obj->m_static_block, false); + if(block) + { + block->m_static_objects.remove(id); + obj->m_static_exists = false; + // Only mark block as modified if data changed considerably + if(shall_be_written) + block->raiseModified(MOD_STATE_WRITE_NEEDED, + "deactivateFarObjects: Static data " + "changed considerably"); + } + } + + // Add to the block where the object is located in + v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS)); + // Get or generate the block + MapBlock *block = m_map->emergeBlock(blockpos); + if(block) { - block->m_static_objects.remove(id); - obj->m_static_exists = false; - // Only mark block as modified if data changed considerably - if(shall_be_written) - block->raiseModified(MOD_STATE_WRITE_NEEDED, - "deactivateFarObjects: Static data " - "changed considerably"); + if(block->m_static_objects.m_stored.size() >= 49){ + errorstream<<"ServerEnv: Trying to store id="<getId() + <<" statically but block "<m_static_objects.m_stored.size() + <<" (over 49) objects." + <<" Forcing delete."<m_static_objects.insert(new_id, s_obj); + + // Only mark block as modified if data changed considerably + if(shall_be_written) + block->raiseModified(MOD_STATE_WRITE_NEEDED, + "deactivateFarObjects: Static data " + "changed considerably"); + + obj->m_static_exists = true; + obj->m_static_block = block->getPos(); + } } - } - - // Add to the block where the object is located in - v3s16 blockpos = getNodeBlockPos(floatToInt(objectpos, BS)); - // Get or generate the block - MapBlock *block = m_map->emergeBlock(blockpos); - - if(block) - { - if(block->m_static_objects.m_stored.size() >= 49){ - errorstream<<"ServerEnv: Trying to store id="<getId() - <<" statically but block "<m_static_objects.m_stored.size() - <<" (over 49) objects." - <<" Forcing delete."<m_static_objects.insert(new_id, s_obj); - - // Only mark block as modified if data changed considerably - if(shall_be_written) - block->raiseModified(MOD_STATE_WRITE_NEEDED, - "deactivateFarObjects: Static data " - "changed considerably"); - - obj->m_static_exists = true; - obj->m_static_block = block->getPos(); + else{ + if(!force_delete){ + errorstream<<"ServerEnv: Could not find or generate " + <<"a block for storing id="<getId() + <<" statically"<getId(), object); - object->addToScene(m_smgr, m_texturesource); + object->addToScene(m_smgr, m_texturesource, m_irr); { // Update lighting immediately u8 light = 0; try{ @@ -2114,7 +2121,8 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object) void ClientEnvironment::addActiveObject(u16 id, u8 type, const std::string &init_data) { - ClientActiveObject* obj = ClientActiveObject::create(type, m_gamedef); + ClientActiveObject* obj = + ClientActiveObject::create(type, m_gamedef, this); if(obj == NULL) { infostream<<"ClientEnvironment::addActiveObject(): " diff --git a/src/environment.h b/src/environment.h index a8b51ae3..fea201bb 100644 --- a/src/environment.h +++ b/src/environment.h @@ -376,7 +376,8 @@ class ClientEnvironment : public Environment { public: ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr, - ITextureSource *texturesource, IGameDef *gamedef); + ITextureSource *texturesource, IGameDef *gamedef, + IrrlichtDevice *device); ~ClientEnvironment(); Map & getMap() @@ -454,6 +455,7 @@ private: scene::ISceneManager *m_smgr; ITextureSource *m_texturesource; IGameDef *m_gamedef; + IrrlichtDevice *m_irr; core::map m_active_objects; Queue m_client_event_queue; IntervalLimiter m_active_object_light_update_interval; diff --git a/src/player.cpp b/src/player.cpp index f26dcba2..937ca9a3 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" #include "environment.h" #include "gamedef.h" +#include "content_sao.h" Player::Player(IGameDef *gamedef): touching_ground(false), @@ -186,7 +187,8 @@ ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env): m_last_good_position_age(0), m_additional_items(), m_inventory_not_sent(false), - m_hp_not_sent(false) + m_hp_not_sent(false), + m_sao(NULL) { } ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 peer_id_, @@ -194,7 +196,8 @@ ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 pee Player(env->getGameDef()), ServerActiveObject(env, pos_), m_inventory_not_sent(false), - m_hp_not_sent(false) + m_hp_not_sent(false), + m_sao(NULL) { setPosition(pos_); peer_id = peer_id_; @@ -203,6 +206,28 @@ ServerRemotePlayer::ServerRemotePlayer(ServerEnvironment *env, v3f pos_, u16 pee ServerRemotePlayer::~ServerRemotePlayer() { clearAddToInventoryLater(); + if(m_sao) + m_sao->setPlayer(NULL); +} + +void ServerRemotePlayer::setPosition(const v3f &position) +{ + Player::setPosition(position); + ServerActiveObject::setBasePosition(position); + if(m_sao) + m_sao->positionUpdated(); +} + +void ServerRemotePlayer::setSAO(PlayerSAO *sao) +{ + infostream<<"ServerRemotePlayer \""<getType() != ACTIVEOBJECT_TYPE_PLAYER) return NULL; - return static_cast(obj); + PlayerSAO *player_sao = static_cast(obj); + return player_sao->getPlayer(); + //return static_cast(obj); } // Exported functions diff --git a/src/server.cpp b/src/server.cpp index 660fdfea..eebf9690 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -48,6 +48,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "craftitemdef.h" #include "mapgen.h" #include "content_abm.h" +#include "content_sao.h" // For PlayerSAO #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" @@ -2218,7 +2219,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } // Get player - Player *player = emergePlayer(playername, peer_id); + ServerRemotePlayer *player = emergePlayer(playername, peer_id); // If failed, cancel if(player == NULL) @@ -2228,6 +2229,10 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) return; } + // Add PlayerSAO + PlayerSAO *sao = new PlayerSAO(m_env, player->getPosition(), player); + m_env->addActiveObject(sao); + /* Answer with a TOCLIENT_INIT */ @@ -4830,12 +4835,13 @@ v3f findSpawnPos(ServerMap &map) return intToFloat(nodepos, BS); } -Player *Server::emergePlayer(const char *name, u16 peer_id) +ServerRemotePlayer *Server::emergePlayer(const char *name, u16 peer_id) { /* Try to get an existing player */ - Player *player = m_env->getPlayer(name); + ServerRemotePlayer *player = + static_cast(m_env->getPlayer(name)); if(player != NULL) { // If player is already connected, cancel @@ -4960,10 +4966,12 @@ void Server::handlePeerChange(PeerChange &c) obj->m_known_by_count--; } + ServerRemotePlayer* player = + static_cast(m_env->getPlayer(c.peer_id)); + // Collect information about leaving in chat std::wstring message; { - Player *player = m_env->getPlayer(c.peer_id); if(player != NULL) { std::wstring name = narrow_to_wide(player->getName()); @@ -4974,21 +4982,26 @@ void Server::handlePeerChange(PeerChange &c) message += L" (timed out)"; } } - - /*// Delete player + + // Remove PlayerSAO + if(player != NULL) { - m_env->removePlayer(c.peer_id); - }*/ - + PlayerSAO *sao = player->getSAO(); + if(sao){ + sao->setPlayer(NULL); + sao->m_removed = true; + } + player->setSAO(NULL); + } + // Set player client disconnected + if(player != NULL) + player->peer_id = 0; + + /* + Print out action + */ { - Player *player = m_env->getPlayer(c.peer_id); - if(player != NULL) - player->peer_id = 0; - - /* - Print out action - */ if(player != NULL) { std::ostringstream os(std::ios_base::binary); diff --git a/src/server.h b/src/server.h index 618b05d9..7568463b 100644 --- a/src/server.h +++ b/src/server.h @@ -599,7 +599,7 @@ private: Call with env and con locked. */ - Player *emergePlayer(const char *name, u16 peer_id); + ServerRemotePlayer *emergePlayer(const char *name, u16 peer_id); // Locks environment and connection by its own struct PeerChange; diff --git a/src/serverobject.h b/src/serverobject.h index b901cbf4..4dac4686 100644 --- a/src/serverobject.h +++ b/src/serverobject.h @@ -58,6 +58,10 @@ public: virtual void addedToEnvironment(){}; // Called before removing from environment virtual void removingFromEnvironment(){}; + // Returns true if object's deletion is the job of the + // environment + virtual bool environmentDeletes() const + { return true; } // Create a certain type of ServerActiveObject static ServerActiveObject* create(u8 type, @@ -112,12 +116,17 @@ public: when it is created (converted from static to active - actually the data is the static form) */ - virtual std::string getStaticData(){return "";} + virtual std::string getStaticData() + { + assert(isStaticAllowed()); + return ""; + } /* Return false in here to never save and instead remove object on unload. getStaticData() will not be called in that case. */ - virtual bool isStaticAllowed(){return true;} + virtual bool isStaticAllowed() const + {return true;} virtual void punch(ServerActiveObject *puncher){} virtual void rightClick(ServerActiveObject *clicker){} @@ -156,12 +165,13 @@ public: bool m_removed; /* - This is set to true when a block should be removed from the active + This is set to true when an object should be removed from the active object list but couldn't be removed because the id has to be reserved for some client. The environment checks this periodically. If this is true and also - m_known_by_count is true, + m_known_by_count is true, object is deleted from the active object + list. */ bool m_pending_deactivation;