diff options
Diffstat (limited to 'src/mapblockobject.h')
-rw-r--r-- | src/mapblockobject.h | 892 |
1 files changed, 892 insertions, 0 deletions
diff --git a/src/mapblockobject.h b/src/mapblockobject.h new file mode 100644 index 000000000..1939cc896 --- /dev/null +++ b/src/mapblockobject.h @@ -0,0 +1,892 @@ +/* +(c) 2010 Perttu Ahola <celeron55@gmail.com> +*/ + +#ifndef MAPBLOCKOBJECT_HEADER +#define MAPBLOCKOBJECT_HEADER + +#include "common_irrlicht.h" +#include <math.h> +#include <string> +#include "serialization.h" +#include "mapnode.h" +#include "constants.h" + +enum +{ + MAPBLOCKOBJECT_TYPE_TEST=0, + MAPBLOCKOBJECT_TYPE_TEST2=1, + MAPBLOCKOBJECT_TYPE_SIGN=2, + MAPBLOCKOBJECT_TYPE_RAT=3, +}; + +class MapBlock; + +class MapBlockObject +{ +public: + MapBlockObject(MapBlock *block, s16 id, v3f pos): + m_collision_box(NULL), + m_selection_box(NULL), + m_block(block), + m_id(id), + m_pos(pos) + { + } + virtual ~MapBlockObject() + { + } + + s16 getId() + { + return m_id; + } + MapBlock* getBlock() + { + return m_block; + } + + // Writes id, pos and typeId + void serializeBase(std::ostream &os, u8 version) + { + u8 buf[6]; + + // id + writeS16(buf, m_id); + os.write((char*)buf, 2); + + // position + // stored as x1000/BS v3s16 + v3s16 pos_i(m_pos.X*1000/BS, m_pos.Y*1000/BS, m_pos.Z*1000/BS); + writeV3S16(buf, pos_i); + os.write((char*)buf, 6); + + // typeId + writeU16(buf, getTypeId()); + os.write((char*)buf, 2); + } + + // Get floating point position on map + v3f getAbsolutePos(); + + void setBlockChanged(); + + // Shootline is relative to block + bool isSelected(core::line3d<f32> shootline) + { + if(m_selection_box == NULL) + return false; + + core::aabbox3d<f32> offsetted_box( + m_selection_box->MinEdge + m_pos, + m_selection_box->MaxEdge + m_pos + ); + + return offsetted_box.intersectsWithLine(shootline); + } + + core::aabbox3d<f32> getSelectionBoxOnMap() + { + v3f absolute_pos = getAbsolutePos(); + + core::aabbox3d<f32> box( + m_selection_box->MinEdge + absolute_pos, + m_selection_box->MaxEdge + absolute_pos + ); + + return box; + } + + /* + Implementation interface + */ + + virtual u16 getTypeId() const = 0; + // Shall call serializeBase and then write the parameters + virtual void serialize(std::ostream &os, u8 version) = 0; + // Shall read parameters from stream + virtual void update(std::istream &is, u8 version) = 0; + + virtual std::string getInventoryString() { return "None"; } + + // Reimplementation shall call this. + virtual void updatePos(v3f pos) + { + m_pos = pos; + } + + // Shall move the object around, modify it and possibly delete it. + // Typical dtimes are 0.2 and 10000. + // A return value of true requests deletion of the object by the caller. + // NOTE: Only server calls this. + virtual bool serverStep(float dtime) { return false; }; + // This should do slight animations only or so + virtual void clientStep(float dtime) {}; + + // NOTE: These functions should do nothing if the asked state is + // same as the current state + // Shall add and remove relevant scene nodes for rendering the + // object in the game world + virtual void addToScene(scene::ISceneManager *smgr) {}; + // Shall remove stuff from the scene + // Should return silently if there is nothing to remove + // NOTE: This has to be called before calling destructor + virtual void removeFromScene() {}; + + virtual std::string infoText() { return ""; } + + // Shall be left NULL if doesn't collide + // Position is relative to m_pos in block + core::aabbox3d<f32> * m_collision_box; + + // Shall be left NULL if can't be selected + core::aabbox3d<f32> * m_selection_box; + +protected: + MapBlock *m_block; + // This differentiates the instance of the object + // Not same as typeId. + s16 m_id; + // Position of the object inside the block + // Units is node coordinates * BS + v3f m_pos; + + friend class MapBlockObjectList; +}; + +class TestObject : public MapBlockObject +{ +public: + // The constructor of every MapBlockObject should be like this + TestObject(MapBlock *block, s16 id, v3f pos): + MapBlockObject(block, id, pos), + m_node(NULL) + { + } + virtual ~TestObject() + { + } + + /* + Implementation interface + */ + virtual u16 getTypeId() const + { + return MAPBLOCKOBJECT_TYPE_TEST; + } + virtual void serialize(std::ostream &os, u8 version) + { + serializeBase(os, version); + + // Write subpos_c * 100 + u8 buf[2]; + writeU16(buf, m_subpos_c * 100); + os.write((char*)buf, 2); + } + virtual void update(std::istream &is, u8 version) + { + // Read subpos_c * 100 + u8 buf[2]; + is.read((char*)buf, 2); + m_subpos_c = (f32)readU16(buf) / 100; + + updateNodePos(); + } + virtual bool serverStep(float dtime) + { + m_subpos_c += dtime * 3.0; + + updateNodePos(); + + return false; + } + virtual void addToScene(scene::ISceneManager *smgr) + { + if(m_node != NULL) + return; + + //dstream<<"Adding to scene"<<std::endl; + + video::IVideoDriver* driver = smgr->getVideoDriver(); + + scene::SMesh *mesh = new scene::SMesh(); + 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_BACK_FACE_CULLING, false); + buf->getMaterial().setTexture + (0, driver->getTexture("../data/player.png")); + buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); + buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + // Add to mesh + mesh->addMeshBuffer(buf); + buf->drop(); + m_node = smgr->addMeshSceneNode(mesh, NULL); + mesh->drop(); + m_node->setPosition(getAbsolutePos()); + } + virtual void removeFromScene() + { + //dstream<<"Removing from scene"<<std::endl; + if(m_node != NULL) + { + m_node->remove(); + m_node = NULL; + } + } + + /* + Special methods + */ + + void updateNodePos() + { + m_subpos = BS*2.0 * v3f(sin(m_subpos_c), sin(m_subpos_c+1.0), sin(-m_subpos_c)); + + if(m_node != NULL) + { + m_node->setPosition(getAbsolutePos() + m_subpos); + } + } + +protected: + scene::IMeshSceneNode *m_node; + std::string m_text; + + v3f m_subpos; + f32 m_subpos_c; +}; + +class MovingObject : public MapBlockObject +{ +public: + // The constructor of every MapBlockObject should be like this + MovingObject(MapBlock *block, s16 id, v3f pos): + MapBlockObject(block, id, pos), + m_speed(0,0,0) + { + m_touching_ground = false; + } + virtual ~MovingObject() + { + } + + /* + Implementation interface + */ + + virtual u16 getTypeId() const = 0; + + virtual void serialize(std::ostream &os, u8 version) + { + serializeBase(os, version); + + u8 buf[6]; + + // Write speed + // stored as x100/BS v3s16 + v3s16 speed_i(m_speed.X*100/BS, m_speed.Y*100/BS, m_speed.Z*100/BS); + writeV3S16(buf, speed_i); + os.write((char*)buf, 6); + } + virtual void update(std::istream &is, u8 version) + { + u8 buf[6]; + + // Read speed + // stored as x100/BS v3s16 + is.read((char*)buf, 6); + v3s16 speed_i = readV3S16(buf); + v3f speed((f32)speed_i.X/100*BS, + (f32)speed_i.Y/100*BS, + (f32)speed_i.Z/100*BS); + + m_speed = speed; + } + + virtual bool serverStep(float dtime) { return false; }; + virtual void clientStep(float dtime) {}; + + virtual void addToScene(scene::ISceneManager *smgr) = 0; + virtual void removeFromScene() = 0; + + /* + Special methods + */ + + // Moves with collision detection + void move(float dtime, v3f acceleration); + +protected: + v3f m_speed; + bool m_touching_ground; +}; + +class Test2Object : public MovingObject +{ +public: + // The constructor of every MapBlockObject should be like this + Test2Object(MapBlock *block, s16 id, v3f pos): + MovingObject(block, id, pos), + m_node(NULL) + { + m_collision_box = new core::aabbox3d<f32> + (-BS*0.3,0,-BS*0.3, BS*0.3,BS*1.7,BS*0.3); + } + virtual ~Test2Object() + { + delete m_collision_box; + } + + /* + Implementation interface + */ + virtual u16 getTypeId() const + { + return MAPBLOCKOBJECT_TYPE_TEST2; + } + virtual void serialize(std::ostream &os, u8 version) + { + MovingObject::serialize(os, version); + } + virtual void update(std::istream &is, u8 version) + { + MovingObject::update(is, version); + + updateNodePos(); + } + + virtual bool serverStep(float dtime) + { + m_speed.X = 2*BS; + m_speed.Z = 0; + + if(m_touching_ground) + { + static float count = 0; + count -= dtime; + if(count < 0.0) + { + count += 1.0; + m_speed.Y = 6.5*BS; + } + } + + move(dtime, v3f(0, -9.81*BS, 0)); + + updateNodePos(); + + return false; + } + + virtual void clientStep(float dtime) + { + m_pos += m_speed * dtime; + + updateNodePos(); + } + + virtual void addToScene(scene::ISceneManager *smgr) + { + if(m_node != NULL) + return; + + //dstream<<"Adding to scene"<<std::endl; + + video::IVideoDriver* driver = smgr->getVideoDriver(); + + scene::SMesh *mesh = new scene::SMesh(); + 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_BACK_FACE_CULLING, false); + buf->getMaterial().setTexture + (0, driver->getTexture("../data/player.png")); + buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); + buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + // Add to mesh + mesh->addMeshBuffer(buf); + buf->drop(); + m_node = smgr->addMeshSceneNode(mesh, NULL); + mesh->drop(); + m_node->setPosition(getAbsolutePos()); + } + virtual void removeFromScene() + { + //dstream<<"Removing from scene"<<std::endl; + if(m_node != NULL) + { + m_node->remove(); + m_node = NULL; + } + } + + /* + Special methods + */ + + void updateNodePos() + { + //m_subpos = BS*2.0 * v3f(sin(m_subpos_c), sin(m_subpos_c+1.0), sin(-m_subpos_c)); + + if(m_node != NULL) + { + //m_node->setPosition(getAbsolutePos() + m_subpos); + m_node->setPosition(getAbsolutePos()); + } + } + +protected: + scene::IMeshSceneNode *m_node; +}; + +class RatObject : public MovingObject +{ +public: + RatObject(MapBlock *block, s16 id, v3f pos): + MovingObject(block, id, pos), + m_node(NULL) + { + m_collision_box = new core::aabbox3d<f32> + (-BS*0.3,0,-BS*0.3, BS*0.3,BS*0.5,BS*0.3); + m_selection_box = new core::aabbox3d<f32> + (-BS*0.3,0,-BS*0.3, BS*0.3,BS*0.5,BS*0.3); + + m_counter1 = 0; + m_counter2 = 0; + } + virtual ~RatObject() + { + delete m_collision_box; + delete m_selection_box; + } + + /* + Implementation interface + */ + virtual u16 getTypeId() const + { + return MAPBLOCKOBJECT_TYPE_RAT; + } + virtual void serialize(std::ostream &os, u8 version) + { + MovingObject::serialize(os, version); + u8 buf[2]; + + // Write yaw * 10 + writeS16(buf, m_yaw * 10); + os.write((char*)buf, 2); + + } + virtual void update(std::istream &is, u8 version) + { + MovingObject::update(is, version); + u8 buf[2]; + + // Read yaw * 10 + is.read((char*)buf, 2); + s16 yaw_i = readS16(buf); + m_yaw = (f32)yaw_i / 10; + + updateNodePos(); + } + + virtual bool serverStep(float dtime) + { + v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI)); + + f32 speed = 2*BS; + + m_speed.X = speed * dir.X; + m_speed.Z = speed * dir.Z; + + if(m_touching_ground && (m_oldpos - m_pos).getLength() < dtime*speed/2) + { + m_counter1 -= dtime; + if(m_counter1 < 0.0) + { + m_counter1 += 1.0; + m_speed.Y = 5.0*BS; + } + } + + { + m_counter2 -= dtime; + if(m_counter2 < 0.0) + { + m_counter2 += (float)(rand()%100)/100*3.0; + m_yaw += ((float)(rand()%200)-100)/100*180; + m_yaw = wrapDegrees(m_yaw); + } + } + + m_oldpos = m_pos; + + //m_yaw += dtime*90; + + move(dtime, v3f(0, -9.81*BS, 0)); + + updateNodePos(); + + return false; + } + + virtual void clientStep(float dtime) + { + m_pos += m_speed * dtime; + + updateNodePos(); + } + + virtual void addToScene(scene::ISceneManager *smgr) + { + if(m_node != NULL) + return; + + video::IVideoDriver* driver = smgr->getVideoDriver(); + + scene::SMesh *mesh = new scene::SMesh(); + 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_BACK_FACE_CULLING, false); + buf->getMaterial().setTexture + (0, driver->getTexture("../data/rat.png")); + buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); + buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + // Add to mesh + mesh->addMeshBuffer(buf); + buf->drop(); + m_node = smgr->addMeshSceneNode(mesh, NULL); + mesh->drop(); + m_node->setPosition(getAbsolutePos()); + } + virtual void removeFromScene() + { + if(m_node != NULL) + { + m_node->remove(); + m_node = NULL; + } + } + + virtual std::string getInventoryString() + { + // There must be a space after the name + // Or does there? + return std::string("Rat "); + } + + /* + Special methods + */ + + void updateNodePos() + { + if(m_node != NULL) + { + m_node->setPosition(getAbsolutePos()); + m_node->setRotation(v3f(0, -m_yaw+180, 0)); + } + } + +protected: + scene::IMeshSceneNode *m_node; + float m_yaw; + + float m_counter1; + float m_counter2; + v3f m_oldpos; +}; + +class SignObject : public MapBlockObject +{ +public: + // The constructor of every MapBlockObject should be like this + SignObject(MapBlock *block, s16 id, v3f pos): + MapBlockObject(block, id, pos), + m_node(NULL) + { + m_selection_box = new core::aabbox3d<f32> + (-BS*0.4,-BS*0.5,-BS*0.4, BS*0.4,BS*0.5,BS*0.4); + } + virtual ~SignObject() + { + delete m_selection_box; + } + + /* + Implementation interface + */ + virtual u16 getTypeId() const + { + return MAPBLOCKOBJECT_TYPE_SIGN; + } + virtual void serialize(std::ostream &os, u8 version) + { + serializeBase(os, version); + u8 buf[2]; + + // Write yaw * 10 + writeS16(buf, m_yaw * 10); + os.write((char*)buf, 2); + + // Write text length + writeU16(buf, m_text.size()); + os.write((char*)buf, 2); + + // Write text + os.write(m_text.c_str(), m_text.size()); + } + virtual void update(std::istream &is, u8 version) + { + u8 buf[2]; + + // Read yaw * 10 + is.read((char*)buf, 2); + s16 yaw_i = readS16(buf); + m_yaw = (f32)yaw_i / 10; + + // Read text length + is.read((char*)buf, 2); + u16 size = readU16(buf); + + // Read text + m_text.clear(); + for(u16 i=0; i<size; i++) + { + is.read((char*)buf, 1); + m_text += buf[0]; + } + + updateSceneNode(); + } + virtual bool serverStep(float dtime) + { + return false; + } + virtual void addToScene(scene::ISceneManager *smgr) + { + if(m_node != NULL) + return; + + video::IVideoDriver* driver = smgr->getVideoDriver(); + + 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,-BS/2,0, 0,0,0, c, 0,1), + video::S3DVertex(-BS/2,-BS/2,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_BACK_FACE_CULLING, false); + buf->getMaterial().setTexture + (0, driver->getTexture("../data/sign.png")); + buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); + buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + // 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,-BS/2,0, 0,0,0, c, 0,1), + video::S3DVertex(BS/2,-BS/2,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_BACK_FACE_CULLING, false); + buf->getMaterial().setTexture + (0, driver->getTexture("../data/sign_back.png")); + buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); + 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(); + + updateSceneNode(); + } + virtual void removeFromScene() + { + if(m_node != NULL) + { + m_node->remove(); + m_node = NULL; + } + } + + virtual std::string infoText() + { + return std::string("\"") + m_text + "\""; + } + + virtual std::string getInventoryString() + { + return std::string("Sign ")+m_text; + } + + /* + Special methods + */ + + void updateSceneNode() + { + if(m_node != NULL) + { + m_node->setPosition(getAbsolutePos()); + m_node->setRotation(v3f(0, m_yaw, 0)); + } + } + + void setText(std::string text) + { + if(text.size() > SIGN_TEXT_MAX_LENGTH) + text = text.substr(0, SIGN_TEXT_MAX_LENGTH); + m_text = text; + + setBlockChanged(); + } + + void setYaw(f32 yaw) + { + m_yaw = yaw; + + setBlockChanged(); + } + +protected: + scene::IMeshSceneNode *m_node; + std::string m_text; + f32 m_yaw; +}; + +struct DistanceSortedObject +{ + DistanceSortedObject(MapBlockObject *a_obj, f32 a_d) + { + obj = a_obj; + d = a_d; + } + + MapBlockObject *obj; + f32 d; + + bool operator < (DistanceSortedObject &other) + { + return d < other.d; + } +}; + +class MapBlockObjectList +{ +public: + MapBlockObjectList(MapBlock *block); + ~MapBlockObjectList(); + // Writes the count, id, the type id and the parameters of all objects + void serialize(std::ostream &os, u8 version); + // Reads ids, type_ids and parameters. + // Creates, updates and deletes objects. + // If smgr!=NULL, new objects are added to the scene + void update(std::istream &is, u8 version, scene::ISceneManager *smgr); + // Finds a new unique id + s16 getFreeId() throw(ContainerFullException); + /* + Adds an object. + Set id to -1 to have this set it to a suitable one. + The block pointer member is set to this block. + */ + void add(MapBlockObject *object) + throw(ContainerFullException, AlreadyExistsException); + + // Deletes and removes all objects + void clear(); + + /* + Removes an object. + Ignores inexistent objects + */ + void remove(s16 id); + /* + References an object. + The object will not be valid after step() or of course if + it is removed. + Grabbing the lock is recommended while processing. + */ + MapBlockObject * get(s16 id); + + // You'll want to grab this in a SharedPtr + JMutexAutoLock * getLock() + { + return new JMutexAutoLock(m_mutex); + } + + // Steps all objects and if server==true, removes those that + // want to be removed + void step(float dtime, bool server); + + // Wraps an object that wants to move onto this block from an another + // Returns true if wrapping was impossible + bool wrapObject(MapBlockObject *object); + + // origin is relative to block + void getObjects(v3f origin, f32 max_d, + core::array<DistanceSortedObject> &dest); + +private: + JMutex m_mutex; + // Key is id + core::map<s16, MapBlockObject*> m_objects; + MapBlock *m_block; +}; + + +#endif + |