From 4b54b291ae2ba5a5f214cadad74f0bed29376f84 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Fri, 8 Apr 2011 00:47:14 +0300 Subject: [PATCH] Some progress on transitioning from MapBlockObject to ActiveObject. --- src/activeobject.h | 1 + src/client.cpp | 42 ++++++++ src/client.h | 8 ++ src/clientobject.cpp | 230 +++++++++++++++++++++++++++++++++++++++---- src/clientobject.h | 77 ++++++++++++++- src/environment.cpp | 30 +++++- src/environment.h | 6 +- src/main.cpp | 90 +++++++++++++++-- src/nodemetadata.cpp | 9 ++ src/server.cpp | 11 ++- src/server.h | 2 +- src/serverobject.cpp | 31 ++++++ src/serverobject.h | 25 ++++- 13 files changed, 522 insertions(+), 40 deletions(-) diff --git a/src/activeobject.h b/src/activeobject.h index 1a16aa0..041be07 100644 --- a/src/activeobject.h +++ b/src/activeobject.h @@ -38,6 +38,7 @@ struct ActiveObjectMessage #define ACTIVEOBJECT_TYPE_INVALID 0 #define ACTIVEOBJECT_TYPE_TEST 1 +#define ACTIVEOBJECT_TYPE_ITEM 2 /* Parent class for ServerActiveObject and ClientActiveObject diff --git a/src/client.cpp b/src/client.cpp index d22f93a..1f2f7e1 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1970,6 +1970,48 @@ MapBlockObject * Client::getSelectedObject( return NULL; } +ClientActiveObject * Client::getSelectedActiveObject( + f32 max_d, + v3f from_pos_f_on_map, + core::line3d shootline_on_map + ) +{ + core::array objects; + + m_env.getActiveObjects(from_pos_f_on_map, max_d, objects); + + //dstream<<"Collected "< *selection_box = obj->getSelectionBox(); + if(selection_box == NULL) + continue; + + v3f pos = obj->getPosition(); + + core::aabbox3d offsetted_box( + selection_box->MinEdge + pos, + selection_box->MaxEdge + pos + ); + + if(offsetted_box.intersectsWithLine(shootline_on_map)) + { + //dstream<<"Returning selected object"< shootline_on_map ); + // Gets closest object pointed by the shootline + // Returns NULL if not found + ClientActiveObject * getSelectedActiveObject( + f32 max_d, + v3f from_pos_f_on_map, + core::line3d shootline_on_map + ); + // Prints a line or two of info void printDebugInfo(std::ostream &os); diff --git a/src/clientobject.cpp b/src/clientobject.cpp index 61ceefb..d95862d 100644 --- a/src/clientobject.cpp +++ b/src/clientobject.cpp @@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "constants.h" #include "utility.h" +core::map ClientActiveObject::m_types; + ClientActiveObject::ClientActiveObject(u16 id): ActiveObject(id) { @@ -35,41 +37,55 @@ ClientActiveObject::~ClientActiveObject() ClientActiveObject* ClientActiveObject::create(u8 type) { - if(type == ACTIVEOBJECT_TYPE_INVALID) + // Find factory function + core::map::Node *n; + n = m_types.find(type); + if(n == NULL) { - dstream<<"ClientActiveObject::create(): passed " - <<"ACTIVEOBJECT_TYPE_INVALID"<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,-BS/4,0, 0,0,0, c, 0,1), + video::S3DVertex(BS/2,-BS/4,0, 0,0,0, c, 1,1), + video::S3DVertex(BS/2,BS/4,0, 0,0,0, c, 1,0), + video::S3DVertex(-BS/2,BS/4,0, 0,0,0, c, 0,0),*/ + video::S3DVertex(BS/3,0,0, 0,0,0, c, 0,1), + video::S3DVertex(-BS/3,0,0, 0,0,0, c, 1,1), + video::S3DVertex(-BS/3,0+BS*2/3,0, 0,0,0, c, 1,0), + video::S3DVertex(BS/3,0+BS*2/3,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, NULL); + buf->getMaterial().setTexture + (0, driver->getTexture(porting::getDataPath("rat.png").c_str())); + 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(); + 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(); +} + +void ItemCAO::removeFromScene() +{ + if(m_node == NULL) + return; + + m_node->remove(); + m_node = NULL; +} + +void ItemCAO::updateLight(u8 light_at_pos) +{ +} + +v3s16 ItemCAO::getLightPosition() +{ + return floatToInt(m_position, BS); +} + +void ItemCAO::updateNodePos() +{ + if(m_node == NULL) + return; + + m_node->setPosition(m_position); +} + +void ItemCAO::step(float dtime) +{ + if(m_node) + { + v3f rot = m_node->getRotation(); + rot.Y += dtime * 120; + m_node->setRotation(rot); + } +} + +void ItemCAO::processMessage(const std::string &data) +{ + dstream<<"ItemCAO: Got data: "<>cmd; + if(cmd == 0) + { + v3f newpos; + is>>newpos.X; + is>>newpos.Y; + is>>newpos.Z; + m_position = newpos; + updateNodePos(); + } +} + +void ItemCAO::initialize(const std::string &data) +{ + dstream<<"ItemCAO: Got init data: "<getMesh(); + + if(mesh == NULL) + return; + + scene::IMeshBuffer *buf = mesh->getMeshBuffer(0); + + if(buf == NULL) + return; + + /* + Create an inventory item to see what is its image + */ + std::istringstream is(m_inventorystring, std::ios_base::binary); + video::ITexture *texture = NULL; + try{ + InventoryItem *item = NULL; + item = InventoryItem::deSerialize(is); + dstream<<__FUNCTION_NAME<<": m_inventorystring=\"" + < item="<getImage(); + delete item; + } + } + catch(SerializationError &e) + { + dstream<<"WARNING: "<<__FUNCTION_NAME + <<": error deSerializing inventorystring \"" + <getMaterial().setTexture(0, texture); + +} + diff --git a/src/clientobject.h b/src/clientobject.h index 226d2f3..ebdcb94 100644 --- a/src/clientobject.h +++ b/src/clientobject.h @@ -46,6 +46,9 @@ public: // 0 <= light_at_pos <= LIGHT_SUN virtual void updateLight(u8 light_at_pos){} virtual v3s16 getLightPosition(){return v3s16(0,0,0);} + virtual core::aabbox3d* getSelectionBox(){return NULL;} + virtual core::aabbox3d* getCollisionBox(){return NULL;} + virtual v3f getPosition(){return v3f(0,0,0);} // Step object in time virtual void step(float dtime){} @@ -54,8 +57,8 @@ public: virtual void processMessage(const std::string &data){} /* - This takes the return value of getClientInitializationData - TODO: Usage of this + This takes the return value of + ServerActiveObject::getClientInitializationData */ virtual void initialize(const std::string &data){} @@ -63,12 +66,37 @@ public: static ClientActiveObject* create(u8 type); protected: + typedef ClientActiveObject* (*Factory)(); + static void registerType(u16 type, Factory f); +private: + static core::map m_types; }; +struct DistanceSortedActiveObject +{ + ClientActiveObject *obj; + f32 d; + + DistanceSortedActiveObject(ClientActiveObject *a_obj, f32 a_d) + { + obj = a_obj; + d = a_d; + } + + bool operator < (DistanceSortedActiveObject &other) + { + return d < other.d; + } +}; + +/* + TestCAO +*/ + class TestCAO : public ClientActiveObject { public: - TestCAO(u16 id); + TestCAO(); virtual ~TestCAO(); u8 getType() const @@ -76,6 +104,8 @@ public: return ACTIVEOBJECT_TYPE_TEST; } + static ClientActiveObject* create(); + void addToScene(scene::ISceneManager *smgr); void removeFromScene(); void updateLight(u8 light_at_pos); @@ -91,5 +121,46 @@ private: v3f m_position; }; +/* + ItemCAO +*/ + +class ItemCAO : public ClientActiveObject +{ +public: + ItemCAO(); + virtual ~ItemCAO(); + + u8 getType() const + { + return ACTIVEOBJECT_TYPE_ITEM; + } + + static ClientActiveObject* create(); + + void addToScene(scene::ISceneManager *smgr); + void removeFromScene(); + void updateLight(u8 light_at_pos); + v3s16 getLightPosition(); + void updateNodePos(); + + void step(float dtime); + + 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; +}; + #endif diff --git a/src/environment.cpp b/src/environment.cpp index d144bae..f4afb28 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -482,7 +482,8 @@ void ServerEnvironment::step(float dtime) m_random_spawn_timer -= dtime; if(m_random_spawn_timer < 0) { - m_random_spawn_timer += myrand_range(2.0, 20.0); + //m_random_spawn_timer += myrand_range(2.0, 20.0); + m_random_spawn_timer += 2.0; /* Find some position @@ -503,11 +504,11 @@ void ServerEnvironment::step(float dtime) ); /* - Create a TestSAO object + Create a ServerActiveObject */ - TestSAO *obj = new TestSAO(this, 0, - v3f(myrand_range(-2*BS,2*BS), BS*5, myrand_range(-2*BS,2*BS))); + //TestSAO *obj = new TestSAO(this, 0, pos); + ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1"); // Add the object to the environment addActiveObject(obj); @@ -1044,6 +1045,27 @@ void ClientEnvironment::processActiveObjectMessage(u16 id, obj->processMessage(data); } +void ClientEnvironment::getActiveObjects(v3f origin, f32 max_d, + core::array &dest) +{ + for(core::map::Iterator + i = m_active_objects.getIterator(); + i.atEnd()==false; i++) + { + ClientActiveObject* obj = i.getNode()->getValue(); + + f32 d = (obj->getPosition() - origin).getLength(); + + if(d > max_d) + continue; + + DistanceSortedActiveObject dso(obj, d); + + dest.push_back(dso); + } +} + + #endif // #ifndef SERVER diff --git a/src/environment.h b/src/environment.h index b415937..9532271 100644 --- a/src/environment.h +++ b/src/environment.h @@ -211,7 +211,11 @@ public: void removeActiveObject(u16 id); void processActiveObjectMessage(u16 id, const std::string &data); - + + // Get all nearby objects + void getActiveObjects(v3f origin, f32 max_d, + core::array &dest); + private: ClientMap *m_map; scene::ISceneManager *m_smgr; diff --git a/src/main.cpp b/src/main.cpp index 46d685a..d3f979c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -109,17 +109,19 @@ Gaming ideas: Game content: ------------- - When furnace is destroyed, move items to player's inventory -- Add lots of stuff, no matter if they have really no real purpose. +- Add lots of stuff - Glass blocks - Growing grass, decaying leaves - - This can be done in the active blocks I guess. - - Lots of stuff can be done in the active blocks. - - Uh, is there an active block list somewhere? + - This can be done in the active blocks I guess. + - Lots of stuff can be done in the active blocks. + - Uh, is there an active block list somewhere? I think not. Add it. - Player health points - - When player dies, throw items on map + - When player dies, throw items on map (needs better item-on-map + implementation) - Cobble to get mossy if near water - More slots in furnace source list, so that multiple ingredients are possible. +- Keys to chests? Documentation: -------------- @@ -200,7 +202,7 @@ FIXME: If something is removed from craftresult with a right click, Objects: -------- -TODO: Get rid of MapBlockObjects +TODO: Get rid of MapBlockObjects and use ActiveObjects Map: ---- @@ -2534,9 +2536,9 @@ int main(int argc, char *argv[]) MapBlockObject *selected_object = client.getSelectedObject (d*BS, camera_position, shootline); - /* - If it's pointing to a MapBlockObject - */ + ClientActiveObject *selected_active_object + = client.getSelectedActiveObject + (d*BS, camera_position, shootline); if(selected_object != NULL) { @@ -2594,6 +2596,76 @@ int main(int argc, char *argv[]) } } } + else if(selected_active_object != NULL) + { + //dstream<<"Client returned selected_active_object != NULL"< *selection_box + = selected_active_object->getSelectionBox(); + // Box should exist because it was returned in the first place + assert(selection_box); + + v3f pos = selected_active_object->getPosition(); + + core::aabbox3d box_on_map( + selection_box->MinEdge + pos, + selection_box->MaxEdge + pos + ); + + hilightboxes.push_back(box_on_map); + + infotext = narrow_to_wide("A ClientActiveObject"); + //infotext = narrow_to_wide(selected_object->infoText()); + + if(g_input->getLeftClicked()) + { + std::cout<getBlock()->getPos(), + selected_object->getId(), g_selected_item); +#endif + } + else if(g_input->getRightClicked()) + { + std::cout<getTypeId() == MAPBLOCKOBJECT_TYPE_SIGN) + { + dstream<<"Sign object right-clicked"<getBlock()->getPos(), + selected_object->getId(), + &client); + + SignObject *sign_object = (SignObject*)selected_object; + + std::wstring wtext = + narrow_to_wide(sign_object->getText()); + + (new GUITextInputMenu(guienv, guiroot, -1, + &g_menumgr, dest, + wtext))->drop(); + } + } + /* + Otherwise pass the event to the server as-is + */ + else + { + client.clickObject(1, selected_object->getBlock()->getPos(), + selected_object->getId(), g_selected_item); + } +#endif + } + } else // selected_object == NULL { diff --git a/src/nodemetadata.cpp b/src/nodemetadata.cpp index be21622..308a338 100644 --- a/src/nodemetadata.cpp +++ b/src/nodemetadata.cpp @@ -99,6 +99,9 @@ void NodeMetadata::registerType(u16 id, Factory f) SignNodeMetadata */ +// Prototype +SignNodeMetadata proto_SignNodeMetadata(""); + SignNodeMetadata::SignNodeMetadata(std::string text): m_text(text) { @@ -130,6 +133,9 @@ std::string SignNodeMetadata::infoText() ChestNodeMetadata */ +// Prototype +ChestNodeMetadata proto_ChestNodeMetadata; + ChestNodeMetadata::ChestNodeMetadata() { NodeMetadata::registerType(typeId(), create); @@ -182,6 +188,9 @@ bool ChestNodeMetadata::nodeRemovalDisabled() FurnaceNodeMetadata */ +// Prototype +FurnaceNodeMetadata proto_FurnaceNodeMetadata; + FurnaceNodeMetadata::FurnaceNodeMetadata() { NodeMetadata::registerType(typeId(), create); diff --git a/src/server.cpp b/src/server.cpp index d25c4a9..20a6a21 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1222,7 +1222,7 @@ void Server::AsyncRunStep() //u16 peer_id = i.getNode()->getKey(); RemoteClient *client = i.getNode()->getValue(); Player *player = m_env.getPlayer(client->peer_id); - std::cout<getName()<<" "; + std::cout<getName()<<"\t"; client->PrintInfo(std::cout); } } @@ -1235,6 +1235,8 @@ void Server::AsyncRunStep() Check added and deleted active objects */ { + //dstream<<"Server: Checking added and deleted active objects"<getValue(); Player *player = m_env.getPlayer(client->peer_id); if(player==NULL) + { + dstream<<"WARNING: "<<__FUNCTION_NAME<<": Client "<peer_id + <<" has no associated player"<getPosition(), BS); core::map removed_objects; @@ -1260,7 +1266,10 @@ void Server::AsyncRunStep() // Ignore if nothing happened if(removed_objects.size() == 0 && added_objects.size() == 0) + { + //dstream<<"INFO: active objects: none changed"< &messages) +{ +} + +std::string ItemSAO::getClientInitializationData() +{ + dstream<<__FUNCTION_NAME< &messages); + std::string getClientInitializationData(); +private: + std::string m_inventorystring; +}; + #endif