new object system
authorPerttu Ahola <celeron55@gmail.com>
Sun, 10 Apr 2011 01:15:10 +0000 (04:15 +0300)
committerPerttu Ahola <celeron55@gmail.com>
Sun, 10 Apr 2011 01:15:10 +0000 (04:15 +0300)
15 files changed:
src/client.cpp
src/client.h
src/clientobject.cpp
src/clientobject.h
src/clientserver.h
src/environment.cpp
src/main.cpp
src/map.cpp
src/mapblock.h
src/nodemetadata.h
src/serialization.h
src/server.cpp
src/serverobject.cpp
src/serverobject.h
src/utility.h

index 1f2f7e1e8e1e6bb7202818d84c0547fc58528e7e..fca7b1b02d61b3843d5962373d90a270ec82b020 100644 (file)
@@ -1193,7 +1193,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
        }
        else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
        {
-               if(g_settings.getBool("enable_experimental"))
+               //if(g_settings.getBool("enable_experimental"))
                {
                        /*
                                u16 command
@@ -1252,7 +1252,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
        }
        else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
        {
-               if(g_settings.getBool("enable_experimental"))
+               //if(g_settings.getBool("enable_experimental"))
                {
                        /*
                                u16 command
@@ -1594,6 +1594,31 @@ void Client::clickObject(u8 button, v3s16 blockpos, s16 id, u16 item)
        Send(0, data, true);
 }
 
+void Client::clickActiveObject(u8 button, u16 id, u16 item)
+{
+       if(connectedAndInitialized() == false){
+               dout_client<<DTIME<<"Client::clickActiveObject() "
+                               "cancelled (not connected)"
+                               <<std::endl;
+               return;
+       }
+       
+       /*
+               length: 7
+               [0] u16 command
+               [2] u8 button (0=left, 1=right)
+               [3] u16 id
+               [5] u16 item
+       */
+       u8 datasize = 2 + 1 + 6 + 2 + 2;
+       SharedBuffer<u8> data(datasize);
+       writeU16(&data[0], TOSERVER_CLICK_ACTIVEOBJECT);
+       writeU8(&data[2], button);
+       writeU16(&data[3], id);
+       writeU16(&data[5], item);
+       Send(0, data, true);
+}
+
 void Client::sendSignText(v3s16 blockpos, s16 id, std::string text)
 {
        /*
index 0616cc914d153aef1de5b7a3eb3b0f9e087b4451..ef3dd435a04b5692dd49dfea576456da82e87893 100644 (file)
@@ -275,6 +275,7 @@ public:
        void groundAction(u8 action, v3s16 nodepos_undersurface,
                        v3s16 nodepos_oversurface, u16 item);
        void clickObject(u8 button, v3s16 blockpos, s16 id, u16 item);
+       void clickActiveObject(u8 button, u16 id, u16 item);
 
        void sendSignText(v3s16 blockpos, s16 id, std::string text);
        void sendSignNodeText(v3s16 p, std::string text);
index d95862d1d5a80ed81a62f127cd8038978bb16da0..a6aa033efcd533993ff0c1d3f01ac8d23f3d36c5 100644 (file)
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "porting.h"
 #include "constants.h"
 #include "utility.h"
+#include "environment.h"
 
 core::map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
 
@@ -148,7 +149,7 @@ void TestCAO::updateNodePos()
        //m_node->setRotation(v3f(0, 45, 0));
 }
 
-void TestCAO::step(float dtime)
+void TestCAO::step(float dtime, ClientEnvironment *env)
 {
        if(m_node)
        {
@@ -187,7 +188,7 @@ ItemCAO proto_ItemCAO;
 
 ItemCAO::ItemCAO():
        ClientActiveObject(0),
-       m_selection_box(-BS*0.4,0.0,-BS*0.4, BS*0.4,BS*0.8,BS*0.4),
+       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))
 {
@@ -219,10 +220,10 @@ void ItemCAO::addToScene(scene::ISceneManager *smgr)
                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),
+               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);
@@ -272,12 +273,17 @@ void ItemCAO::updateNodePos()
        m_node->setPosition(m_position);
 }
 
-void ItemCAO::step(float dtime)
+void ItemCAO::step(float dtime, ClientEnvironment *env)
 {
        if(m_node)
        {
-               v3f rot = m_node->getRotation();
+               /*v3f rot = m_node->getRotation();
                rot.Y += dtime * 120;
+               m_node->setRotation(rot);*/
+               LocalPlayer *player = env->getLocalPlayer();
+               assert(player);
+               v3f rot = m_node->getRotation();
+               rot.Y = 180.0 - (player->getYaw());
                m_node->setRotation(rot);
        }
 }
index ebdcb948eae6f44585726596b147d07370a5372c..50fae67c287bb7f20f194256ec08d9e06e0f3d4a 100644 (file)
@@ -35,6 +35,8 @@ Some planning
 
 */
 
+class ClientEnvironment;
+
 class ClientActiveObject : public ActiveObject
 {
 public:
@@ -51,11 +53,13 @@ public:
        virtual v3f getPosition(){return v3f(0,0,0);}
        
        // Step object in time
-       virtual void step(float dtime){}
+       virtual void step(float dtime, ClientEnvironment *env){}
        
        // Process a message sent by the server side object
        virtual void processMessage(const std::string &data){}
 
+       virtual std::string infoText() {return "";}
+
        /*
                This takes the return value of
                ServerActiveObject::getClientInitializationData
@@ -66,9 +70,11 @@ public:
        static ClientActiveObject* create(u8 type);
 
 protected:
+       // Used for creating objects based on type
        typedef ClientActiveObject* (*Factory)();
        static void registerType(u16 type, Factory f);
 private:
+       // Used for creating objects based on type
        static core::map<u16, Factory> m_types;
 };
 
@@ -112,7 +118,7 @@ public:
        v3s16 getLightPosition();
        void updateNodePos();
 
-       void step(float dtime);
+       void step(float dtime, ClientEnvironment *env);
 
        void processMessage(const std::string &data);
 
@@ -144,7 +150,7 @@ public:
        v3s16 getLightPosition();
        void updateNodePos();
 
-       void step(float dtime);
+       void step(float dtime, ClientEnvironment *env);
 
        void processMessage(const std::string &data);
 
index 7baa79fa64fa18453bafd8ea2aeda0db2bb30a24..fadafed5fe4dbe53b82a0dc7794eaacd9eea476d 100644 (file)
@@ -249,6 +249,15 @@ enum ToServerCommand
                textdata
        */
 
+       TOSERVER_CLICK_ACTIVEOBJECT = 0x34,
+       /*
+               length: 7
+               [0] u16 command
+               [2] u8 button (0=left, 1=right)
+               [3] u16 id
+               [5] u16 item
+       */
+
 };
 
 inline SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time)
index f4afb28bf63de5e0114a37670dd3494a3c666cd7..7e1d268df05c4897e7ba9c3ba0efef3215c697af 100644 (file)
@@ -189,7 +189,7 @@ u32 Environment::getDayNightRatio()
 ServerEnvironment::ServerEnvironment(ServerMap *map, Server *server):
        m_map(map),
        m_server(server),
-       m_random_spawn_timer(0)
+       m_random_spawn_timer(3)
 {
 }
 
@@ -422,7 +422,7 @@ void ServerEnvironment::step(float dtime)
                }
        }
        
-       if(g_settings.getBool("enable_experimental"))
+       //if(g_settings.getBool("enable_experimental"))
        {
 
        /*
@@ -438,7 +438,7 @@ void ServerEnvironment::step(float dtime)
        }
 
        /*
-               Remove (m_removed && m_known_by_count==0) objects
+               Remove objects that satisfy (m_removed && m_known_by_count==0)
        */
        {
                core::list<u16> objects_to_remove;
@@ -457,16 +457,173 @@ void ServerEnvironment::step(float dtime)
                                objects_to_remove.push_back(id);
                                continue;
                        }
-                       else
+                       // If not m_removed, don't remove.
+                       if(obj->m_removed == false)
+                               continue;
+                       // Delete
+                       delete obj;
+                       // Id to be removed from m_active_objects
+                       objects_to_remove.push_back(id);
+               }
+               // Remove references from m_active_objects
+               for(core::list<u16>::Iterator i = objects_to_remove.begin();
+                               i != objects_to_remove.end(); i++)
+               {
+                       m_active_objects.remove(*i);
+               }
+       }
+       
+
+       const s16 to_active_max_blocks = 3;
+       const f32 to_static_max_f = (to_active_max_blocks+1)*MAP_BLOCKSIZE*BS;
+
+       /*
+               Convert stored objects from blocks near the players to active.
+       */
+       for(core::list<Player*>::Iterator i = m_players.begin();
+                       i != m_players.end(); i++)
+       {
+               Player *player = *i;
+               v3f playerpos = player->getPosition();
+               
+               v3s16 blockpos0 = getNodeBlockPos(floatToInt(playerpos, BS));
+               v3s16 bpmin = blockpos0 - v3s16(1,1,1)*to_active_max_blocks;
+               v3s16 bpmax = blockpos0 + v3s16(1,1,1)*to_active_max_blocks;
+               // Loop through all nearby blocks
+               for(s16 x=bpmin.X; x<=bpmax.X; x++)
+               for(s16 y=bpmin.Y; y<=bpmax.Y; y++)
+               for(s16 z=bpmin.Z; z<=bpmax.Z; z++)
+               {
+                       v3s16 blockpos(x,y,z);
+                       MapBlock *block = m_map->getBlockNoCreateNoEx(blockpos);
+                       if(block==NULL)
+                               continue;
+                       // Ignore if no stored objects (to not set changed flag)
+                       if(block->m_static_objects.m_stored.size() == 0)
+                               continue;
+                       // This will contain the leftovers of the stored list
+                       core::list<StaticObject> new_stored;
+                       // Loop through stored static objects
+                       for(core::list<StaticObject>::Iterator
+                                       i = block->m_static_objects.m_stored.begin();
+                                       i != block->m_static_objects.m_stored.end(); i++)
                        {
-                               // If not m_removed, don't remove.
-                               if(obj->m_removed == false)
+                               dstream<<"INFO: Server: Creating an active object from "
+                                               <<"static data"<<std::endl;
+                               StaticObject &s_obj = *i;
+                               // Create an active object from the data
+                               ServerActiveObject *obj = ServerActiveObject::create
+                                               (s_obj.type, this, 0, s_obj.pos, s_obj.data);
+                               if(obj==NULL)
+                               {
+                                       // This is necessary to preserve stuff during bugs
+                                       // and errors
+                                       new_stored.push_back(s_obj);
                                        continue;
-                               // Delete
-                               delete obj;
-                               // Id to be removed from m_active_objects
-                               objects_to_remove.push_back(id);
+                               }
+                               // This will also add the object to the active static list
+                               addActiveObject(obj);
+                               //u16 id = addActiveObject(obj);
+                       }
+                       // Clear stored list
+                       block->m_static_objects.m_stored.clear();
+                       // Add leftover stuff to stored list
+                       for(core::list<StaticObject>::Iterator
+                                       i = new_stored.begin();
+                                       i != new_stored.end(); i++)
+                       {
+                               StaticObject &s_obj = *i;
+                               block->m_static_objects.m_stored.push_back(s_obj);
+                       }
+                       block->setChangedFlag();
+               }
+       }
+
+       /*
+               Convert objects that are far away from all the players to static.
+       */
+       {
+               core::list<u16> objects_to_remove;
+               for(core::map<u16, ServerActiveObject*>::Iterator
+                               i = m_active_objects.getIterator();
+                               i.atEnd()==false; i++)
+               {
+                       ServerActiveObject* obj = i.getNode()->getValue();
+                       u16 id = i.getNode()->getKey();
+                       v3f objectpos = obj->getBasePosition();
+
+                       // This shouldn't happen but check it
+                       if(obj == NULL)
+                       {
+                               dstream<<"WARNING: NULL object found in ServerEnvironment"
+                                               <<std::endl;
+                               continue;
                        }
+                       // If known by some client, don't convert to static.
+                       if(obj->m_known_by_count > 0)
+                               continue;
+
+                       // If close to some player, don't convert to static.
+                       bool close_to_player = false;
+                       for(core::list<Player*>::Iterator i = m_players.begin();
+                                       i != m_players.end(); i++)
+                       {
+                               Player *player = *i;
+                               v3f playerpos = player->getPosition();
+                               f32 d = playerpos.getDistanceFrom(objectpos);
+                               if(d < to_static_max_f)
+                               {
+                                       close_to_player = true;
+                                       break;
+                               }
+                       }
+
+                       if(close_to_player)
+                               continue;
+
+                       /*
+                               Update the static data and remove the active object.
+                       */
+
+                       // Delete old static object
+                       MapBlock *oldblock = NULL;
+                       if(obj->m_static_exists)
+                       {
+                               MapBlock *block = m_map->getBlockNoCreateNoEx(obj->m_static_block);
+                               if(block)
+                               {
+                                       block->m_static_objects.remove(id);
+                                       oldblock = block;
+                               }
+                       }
+                       // Add new static object
+                       std::string staticdata = obj->getStaticData();
+                       StaticObject s_obj(obj->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.insert(0, s_obj);
+                               block->setChangedFlag();
+                       }
+                       // If not possible, add back to previous block
+                       else if(oldblock)
+                       {
+                               oldblock->m_static_objects.insert(0, s_obj);
+                               oldblock->setChangedFlag();
+                       }
+                       else{
+                               dstream<<"WARNING: Server: Could not find a block for "
+                                               <<"storing static object"<<std::endl;
+                               continue;
+                       }
+                       // Delete active object
+                       dstream<<"INFO: Server: Stored static data. Deleting object."
+                                       <<std::endl;
+                       delete obj;
+                       // Id to be removed from m_active_objects
+                       objects_to_remove.push_back(id);
                }
                // Remove references from m_active_objects
                for(core::list<u16>::Iterator i = objects_to_remove.begin();
@@ -479,11 +636,13 @@ void ServerEnvironment::step(float dtime)
        /*
                TEST CODE
        */
+#if 1
        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 += 2.0;
+               //m_random_spawn_timer += 2.0;
+               m_random_spawn_timer += 200.0;
 
                /*
                        Find some position
@@ -508,11 +667,10 @@ void ServerEnvironment::step(float dtime)
                */
 
                //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);
+               //ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1");
+               //addActiveObject(obj);
        }
+#endif
 
        } // enable_experimental
 }
@@ -582,7 +740,25 @@ u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
        }
        dstream<<"INGO: ServerEnvironment::addActiveObject(): "
                        <<"added (id="<<object->getId()<<")"<<std::endl;
+                       
        m_active_objects.insert(object->getId(), object);
+
+       // 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);
+       }
+       else{
+               dstream<<"WARNING: Server: Could not find a block for "
+                               <<"storing newly added static active object"<<std::endl;
+       }
+
        return object->getId();
 }
 
@@ -912,7 +1088,7 @@ void ClientEnvironment::step(float dtime)
        {
                ClientActiveObject* obj = i.getNode()->getValue();
                // Step object
-               obj->step(dtime);
+               obj->step(dtime, this);
        }
 }
 
index d3f979cac8d833ca7c1fb4ec37338e2ba52e641a..7749266d9f1b4d40a3f4d02acaa3cd2f98607cf2 100644 (file)
@@ -2620,10 +2620,8 @@ int main(int argc, char *argv[])
                        if(g_input->getLeftClicked())\r
                        {\r
                                std::cout<<DTIME<<"Left-clicked object"<<std::endl;\r
-#if 0\r
-                               client.clickObject(0, selected_object->getBlock()->getPos(),\r
-                                               selected_object->getId(), g_selected_item);\r
-#endif\r
+                               client.clickActiveObject(0,\r
+                                               selected_active_object->getId(), g_selected_item);\r
                        }\r
                        else if(g_input->getRightClicked())\r
                        {\r
@@ -2634,26 +2632,6 @@ int main(int argc, char *argv[])
                                */\r
                                if(selected_object->getTypeId() == MAPBLOCKOBJECT_TYPE_SIGN)\r
                                {\r
-                                       dstream<<"Sign object right-clicked"<<std::endl;\r
-                                       \r
-                                       if(random_input == false)\r
-                                       {\r
-                                               // Get a new text for it\r
-\r
-                                               TextDest *dest = new TextDestSign(\r
-                                                               selected_object->getBlock()->getPos(),\r
-                                                               selected_object->getId(),\r
-                                                               &client);\r
-\r
-                                               SignObject *sign_object = (SignObject*)selected_object;\r
-\r
-                                               std::wstring wtext =\r
-                                                               narrow_to_wide(sign_object->getText());\r
-\r
-                                               (new GUITextInputMenu(guienv, guiroot, -1,\r
-                                                               &g_menumgr, dest,\r
-                                                               wtext))->drop();\r
-                                       }\r
                                }\r
                                /*\r
                                        Otherwise pass the event to the server as-is\r
index 49ed2f5feaf427678396561e129220296fb7c0ca..59cf937c0aef0ceacb55e0b2bd894ff12040cf1f 100644 (file)
@@ -5239,6 +5239,14 @@ void ServerMap::saveBlock(MapBlock *block)
                block->serializeObjects(o, version);
        }
        
+       /*
+               Versions up from 15 have static objects.
+       */
+       if(version >= 15)
+       {
+               block->m_static_objects.serialize(o);
+       }
+       
        // We just wrote it to the disk
        block->resetChangedFlag();
 }
@@ -5296,6 +5304,14 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
                        block->updateObjects(is, version, NULL, 0);
                }
 
+               /*
+                       Versions up from 15 have static objects.
+               */
+               if(version >= 15)
+               {
+                       block->m_static_objects.deSerialize(is);
+               }
+               
                if(created_new)
                        sector->insertBlock(block);
                
index a77bf40c06c794c4b7cfc49da7f431e84bca6735..ce56825683b3255ee2e5b5f73e7c0e34562fe46a 100644 (file)
@@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mapblockobject.h"
 #include "voxel.h"
 #include "nodemetadata.h"
+#include "staticobject.h"
 
 
 // Named by looking towards z+
@@ -681,6 +682,7 @@ public:
 #endif
        
        NodeMetadataList m_node_metadata;
+       StaticObjectList m_static_objects;
        
 private:
        /*
index e56bff17fba372ed6c861d7281f41352bd3ad947..ae02cfc3c2cbd8f294f1d7187c806af51a5b8f4c 100644 (file)
@@ -54,7 +54,7 @@ public:
        virtual u16 typeId() const = 0;
        virtual NodeMetadata* clone() = 0;
        virtual void serializeBody(std::ostream &os) = 0;
-       virtual std::string infoText() {return "<todo: remove this text>";}
+       virtual std::string infoText() {return "";}
        virtual Inventory* getInventory() {return NULL;}
        // This is called always after the inventory is modified, before
        // the changes are copied elsewhere
index fed5bb5223fb77a923e675dd2a0c96bf1a1ab23d..7b5c7d418e12970b59d34911bf14b4ea2f3f9705 100644 (file)
@@ -47,11 +47,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
        12: (dev) UnlimitedHeightmap now uses interpolated areas
        13: (dev) Mapgen v2
        14: (dev) NodeMetadata
+       15: (dev) StaticObjects
 */
 // This represents an uninitialized or invalid format
 #define SER_FMT_VER_INVALID 255
 // Highest supported serialization version
-#define SER_FMT_VER_HIGHEST 14
+#define SER_FMT_VER_HIGHEST 15
 // Lowest supported serialization version
 #define SER_FMT_VER_LOWEST 2
 
index 20a6a21c38f8d64ca20a4b1a4e6c12ddab91b181..ab4032743121a8abcf34447303a4ae9db475227a 100644 (file)
@@ -1228,7 +1228,7 @@ void Server::AsyncRunStep()
                }
        }
 
-       if(g_settings.getBool("enable_experimental"))
+       //if(g_settings.getBool("enable_experimental"))
        {
 
        /*
@@ -1345,6 +1345,33 @@ void Server::AsyncRunStep()
                                        <<added_objects.size()<<" added, "
                                        <<"packet size is "<<reply.getSize()<<std::endl;
                }
+
+#if 0
+               /*
+                       Collect a list of all the objects known by the clients
+                       and report it back to the environment.
+               */
+
+               core::map<u16, bool> all_known_objects;
+
+               for(core::map<u16, RemoteClient*>::Iterator
+                       i = m_clients.getIterator();
+                       i.atEnd() == false; i++)
+               {
+                       RemoteClient *client = i.getNode()->getValue();
+                       // Go through all known objects of client
+                       for(core::map<u16, bool>::Iterator
+                                       i = client->m_known_objects.getIterator();
+                                       i.atEnd()==false; i++)
+                       {
+                               u16 id = i.getNode()->getKey();
+                               all_known_objects[id] = true;
+                       }
+               }
+               
+               m_env.setKnownActiveObjects(whatever);
+#endif
+
        }
 
        /*
@@ -1978,6 +2005,70 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        block->removeObject(id);
                }
        }
+       else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
+       {
+               if(datasize < 7)
+                       return;
+
+               /*
+                       length: 7
+                       [0] u16 command
+                       [2] u8 button (0=left, 1=right)
+                       [3] u16 id
+                       [5] u16 item
+               */
+               u8 button = readU8(&data[2]);
+               u16 id = readS16(&data[3]);
+               //u16 item_i = readU16(&data[11]);
+       
+               ServerActiveObject *obj = m_env.getActiveObject(id);
+
+               if(obj == NULL)
+               {
+                       derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
+                                       <<std::endl;
+                       return;
+               }
+
+               //TODO: Check that object is reasonably close
+               
+               // Left click, pick object up (usually)
+               if(button == 0)
+               {
+                       InventoryList *ilist = player->inventory.getList("main");
+                       if(g_settings.getBool("creative_mode") == false && ilist != NULL)
+                       {
+                       
+                               // Skip if inventory has no free space
+                               if(ilist->getUsedSlots() == ilist->getSize())
+                               {
+                                       dout_server<<"Player inventory has no free space"<<std::endl;
+                                       return;
+                               }
+                               
+                               /*
+                                       Create the inventory item
+                               */
+                               InventoryItem *item = NULL;
+                               // If it is an item-object, take the item from it
+                               if(obj->getType() == ACTIVEOBJECT_TYPE_ITEM
+                                               && obj->m_removed == false)
+                               {
+                                       item = ((ItemSAO*)obj)->createInventoryItem();
+                               }
+                               
+                               if(item)
+                               {
+                                       // Add to inventory and send inventory
+                                       ilist->addItem(item);
+                                       SendInventory(player->peer_id);
+                               }
+                       }
+
+                       // Remove object from environment
+                       obj->m_removed = true;
+               }
+       }
        else if(command == TOSERVER_GROUND_ACTION)
        {
                if(datasize < 17)
@@ -2327,68 +2418,40 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                }*/
                        }
                        /*
-                               Handle other items
+                               Place other item (not a block)
                        */
                        else
                        {
                                v3s16 blockpos = getNodeBlockPos(p_over);
-
-                               MapBlock *block = NULL;
-                               try
-                               {
-                                       block = m_env.getMap().getBlockNoCreate(blockpos);
-                               }
-                               catch(InvalidPositionException &e)
+                               
+                               /*
+                                       Check that the block is loaded so that the item
+                                       can properly be added to the static list too
+                               */
+                               MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
+                               if(block==NULL)
                                {
                                        derr_server<<"Error while placing object: "
                                                        "block not found"<<std::endl;
                                        return;
                                }
 
-                               v3s16 block_pos_i_on_map = block->getPosRelative();
-                               v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
-
                                v3f pos = intToFloat(p_over, BS);
-                               pos -= block_pos_f_on_map;
-                               
-                               /*dout_server<<"pos="
-                                               <<"("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
-                                               <<std::endl;*/
+                               pos.Y -= BS*0.45;
 
-                               MapBlockObject *obj = NULL;
-
-                               /*
-                                       Handle block object items
-                               */
-                               if(std::string("MBOItem") == item->getName())
-                               {
-                                       MapBlockObjectItem *oitem = (MapBlockObjectItem*)item;
-
-                                       /*dout_server<<"Trying to place a MapBlockObjectItem: "
-                                                       "inventorystring=\""
-                                                       <<oitem->getInventoryString()
-                                                       <<"\""<<std::endl;*/
-                                                       
-                                       obj = oitem->createObject
-                                                       (pos, player->getYaw(), player->getPitch());
-                               }
+                               dout_server<<"Placing a miscellaneous item on map"
+                                               <<std::endl;
+                                               
                                /*
-                                       Handle other items
+                                       Create an ItemSAO
                                */
-                               else
-                               {
-                                       dout_server<<"Placing a miscellaneous item on map"
-                                                       <<std::endl;
-                                       /*
-                                               Create an ItemObject that contains the item.
-                                       */
-                                       ItemObject *iobj = new ItemObject(NULL, -1, pos);
-                                       std::ostringstream os(std::ios_base::binary);
-                                       item->serialize(os);
-                                       dout_server<<"Item string is \""<<os.str()<<"\""<<std::endl;
-                                       iobj->setItemString(os.str());
-                                       obj = iobj;
-                               }
+                               // Get item string
+                               std::ostringstream os(std::ios_base::binary);
+                               item->serialize(os);
+                               dout_server<<"Item string is \""<<os.str()<<"\""<<std::endl;
+                               // Create object
+                               ServerActiveObject *obj = new ItemSAO
+                                               (&m_env, 0, pos, os.str());
 
                                if(obj == NULL)
                                {
@@ -2398,8 +2461,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                }
                                else
                                {
-                                       block->addObject(obj);
-
+                                       // Add the object to the environment
+                                       m_env.addActiveObject(obj);
+                                       
                                        dout_server<<"Placed object"<<std::endl;
 
                                        InventoryList *ilist = player->inventory.getList("main");
@@ -3874,30 +3938,6 @@ Player *Server::emergePlayer(const char *name, const char *password,
        } // create new player
 }
 
-#if 0
-void Server::UpdateBlockWaterPressure(MapBlock *block,
-                       core::map<v3s16, MapBlock*> &modified_blocks)
-{
-       MapVoxelManipulator v(&m_env.getMap());
-       v.m_disable_water_climb =
-                       g_settings.getBool("disable_water_climb");
-       
-       VoxelArea area(block->getPosRelative(),
-                       block->getPosRelative() + v3s16(1,1,1)*(MAP_BLOCKSIZE-1));
-
-       try
-       {
-               v.updateAreaWaterPressure(area, m_flow_active_nodes);
-       }
-       catch(ProcessingLimitException &e)
-       {
-               dstream<<"Processing limit reached (1)"<<std::endl;
-       }
-       
-       v.blitBack(modified_blocks);
-}
-#endif
-
 void Server::handlePeerChange(PeerChange &c)
 {
        JMutexAutoLock envlock(m_env_mutex);
index 3645f76669684c104c70aacc0bc35237df8f0321..f0ef7d8d60225135ca31514305926e6fe3695377 100644 (file)
@@ -20,11 +20,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "serverobject.h"
 #include <fstream>
 #include "environment.h"
+#include "inventory.h"
+
+core::map<u16, ServerActiveObject::Factory> ServerActiveObject::m_types;
 
 ServerActiveObject::ServerActiveObject(ServerEnvironment *env, u16 id, v3f pos):
        ActiveObject(id),
        m_known_by_count(0),
        m_removed(false),
+       m_static_exists(false),
+       m_static_block(1337,1337,1337),
        m_env(env),
        m_base_position(pos)
 {
@@ -34,15 +39,55 @@ ServerActiveObject::~ServerActiveObject()
 {
 }
 
+ServerActiveObject* ServerActiveObject::create(u8 type,
+               ServerEnvironment *env, u16 id, v3f pos,
+               const std::string &data)
+{
+       // Find factory function
+       core::map<u16, Factory>::Node *n;
+       n = m_types.find(type);
+       if(n == NULL)
+       {
+               // If factory is not found, just return.
+               dstream<<"WARNING: ServerActiveObject: No factory for type="
+                               <<type<<std::endl;
+               return NULL;
+       }
+
+       Factory f = n->getValue();
+       ServerActiveObject *object = (*f)(env, id, pos, data);
+       return object;
+}
+
+void ServerActiveObject::registerType(u16 type, Factory f)
+{
+       core::map<u16, Factory>::Node *n;
+       n = m_types.find(type);
+       if(n)
+               return;
+       m_types.insert(type, f);
+}
+
+
 /*
        TestSAO
 */
 
+// Prototype
+TestSAO proto_TestSAO(NULL, 0, v3f(0,0,0));
+
 TestSAO::TestSAO(ServerEnvironment *env, u16 id, v3f pos):
        ServerActiveObject(env, id, pos),
        m_timer1(0),
        m_age(0)
 {
+       ServerActiveObject::registerType(getType(), create);
+}
+
+ServerActiveObject* TestSAO::create(ServerEnvironment *env, u16 id, v3f pos,
+               const std::string &data)
+{
+       return new TestSAO(env, id, pos);
 }
 
 void TestSAO::step(float dtime, Queue<ActiveObjectMessage> &messages)
@@ -84,6 +129,9 @@ void TestSAO::step(float dtime, Queue<ActiveObjectMessage> &messages)
        ItemSAO
 */
 
+// Prototype
+ItemSAO proto_ItemSAO(NULL, 0, v3f(0,0,0), "");
+
 ItemSAO::ItemSAO(ServerEnvironment *env, u16 id, v3f pos,
                const std::string inventorystring):
        ServerActiveObject(env, id, pos),
@@ -91,6 +139,19 @@ ItemSAO::ItemSAO(ServerEnvironment *env, u16 id, v3f pos,
 {
        dstream<<"Server: ItemSAO created with inventorystring=\""
                        <<m_inventorystring<<"\""<<std::endl;
+       ServerActiveObject::registerType(getType(), create);
+}
+
+ServerActiveObject* ItemSAO::create(ServerEnvironment *env, u16 id, v3f pos,
+               const std::string &data)
+{
+       std::istringstream is(data, std::ios::binary);
+       char buf[1];
+       is.read(buf, 1); // read version
+       std::string inventorystring = deSerializeString(is);
+       dstream<<"ItemSAO::create(): Creating item \""
+                       <<inventorystring<<"\""<<std::endl;
+       return new ItemSAO(env, id, pos, inventorystring);
 }
 
 void ItemSAO::step(float dtime, Queue<ActiveObjectMessage> &messages)
@@ -111,4 +172,34 @@ std::string ItemSAO::getClientInitializationData()
        return data;
 }
 
+std::string ItemSAO::getStaticData()
+{
+       dstream<<__FUNCTION_NAME<<std::endl;
+       std::ostringstream os(std::ios::binary);
+       char buf[1];
+       buf[0] = 0; //version
+       os.write(buf, 1);
+       os<<serializeString(m_inventorystring);
+       return os.str();
+}
+
+InventoryItem * ItemSAO::createInventoryItem()
+{
+       try{
+               std::istringstream is(m_inventorystring, std::ios_base::binary);
+               InventoryItem *item = InventoryItem::deSerialize(is);
+               dstream<<__FUNCTION_NAME<<": m_inventorystring=\""
+                               <<m_inventorystring<<"\" -> item="<<item
+                               <<std::endl;
+               return item;
+       }
+       catch(SerializationError &e)
+       {
+               dstream<<__FUNCTION_NAME<<": serialization error: "
+                               <<"m_inventorystring=\""<<m_inventorystring<<"\""<<std::endl;
+               return NULL;
+       }
+}
+
+
 
index 241458193f1bc735e5d55b535640caef97242345..a307c421fb0a61c7bd9ccd2203f5143a8c4044ae 100644 (file)
@@ -39,27 +39,28 @@ Some planning
 */
 
 class ServerEnvironment;
+class InventoryItem;
 
 class ServerActiveObject : public ActiveObject
 {
 public:
-       ServerActiveObject(ServerEnvironment *env, u16 id, v3f pos=v3f(0,0,0));
+       ServerActiveObject(ServerEnvironment *env, u16 id, v3f pos);
        virtual ~ServerActiveObject();
 
-       v3f getBasePosition()
-       {
-               return m_base_position;
-       }
+       // Create a certain type of ServerActiveObject
+       static ServerActiveObject* create(u8 type,
+                       ServerEnvironment *env, u16 id, v3f pos,
+                       const std::string &data);
        
+       /*
+               Some simple getters/setters
+       */
+       v3f getBasePosition()
+               {return m_base_position;}
        void setBasePosition(v3f pos)
-       {
-               m_base_position = pos;
-       }
-
+               {m_base_position = pos;}
        ServerEnvironment* getEnv()
-       {
-               return m_env;
-       }
+               {return m_env;}
        
        /*
                Step object in time.
@@ -75,14 +76,10 @@ public:
        
        /*
                The return value of this is passed to the server-side object
-               when it is loaded from disk or from a static object
-       */
-       virtual std::string getServerInitializationData(){return "";}
-       
-       /*
-               This takes the return value of getServerInitializationData
+               when it is created (converted from static to active - actually
+               the data is the static form)
        */
-       virtual void initialize(const std::string &data){}
+       virtual std::string getStaticData(){return "";}
        
        // Number of players which know about this object
        u16 m_known_by_count;
@@ -93,12 +90,33 @@ public:
                  it could be confused to some other object by some client.
                - This is set to true by the step() method when the object wants
                  to be deleted.
+               - This can be set to true by anything else too.
        */
        bool m_removed;
        
+       /*
+               Whether the object's static data has been stored to a block
+       */
+       bool m_static_exists;
+       /*
+               The block from which the object was loaded from, and in which
+               a copy of the static data resides.
+       */
+       v3s16 m_static_block;
+       
 protected:
+       // Used for creating objects based on type
+       typedef ServerActiveObject* (*Factory)
+                       (ServerEnvironment *env, u16 id, v3f pos,
+                       const std::string &data);
+       static void registerType(u16 type, Factory f);
+
        ServerEnvironment *m_env;
        v3f m_base_position;
+
+private:
+       // Used for creating objects based on type
+       static core::map<u16, Factory> m_types;
 };
 
 class TestSAO : public ServerActiveObject
@@ -106,9 +124,9 @@ class TestSAO : public ServerActiveObject
 public:
        TestSAO(ServerEnvironment *env, u16 id, v3f pos);
        u8 getType() const
-       {
-               return ACTIVEOBJECT_TYPE_TEST;
-       }
+               {return ACTIVEOBJECT_TYPE_TEST;}
+       static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
+                       const std::string &data);
        void step(float dtime, Queue<ActiveObjectMessage> &messages);
 private:
        float m_timer1;
@@ -121,11 +139,13 @@ public:
        ItemSAO(ServerEnvironment *env, u16 id, v3f pos,
                        const std::string inventorystring);
        u8 getType() const
-       {
-               return ACTIVEOBJECT_TYPE_ITEM;
-       }
+               {return ACTIVEOBJECT_TYPE_ITEM;}
+       static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
+                       const std::string &data);
        void step(float dtime, Queue<ActiveObjectMessage> &messages);
        std::string getClientInitializationData();
+       std::string getStaticData();
+       InventoryItem* createInventoryItem();
 private:
        std::string m_inventorystring;
 };
index 3640b4b518fa8d02892add275067f2c69eacb69f..2b143f0bac4aa03fdb6cb276f6b575bef96dd402 100644 (file)
@@ -1839,15 +1839,17 @@ inline std::string serializeString(const std::string plain)
        return s;
 }
 
-// Reads a string with the length as the first two bytes
+/*// Reads a string with the length as the first two bytes
 inline std::string deSerializeString(const std::string encoded)
 {
        u16 s_size = readU16((u8*)&encoded.c_str()[0]);
+       if(s_size > encoded.length() - 2)
+               return "";
        std::string s;
        s.reserve(s_size);
        s.append(&encoded.c_str()[2], s_size);
        return s;
-}
+}*/
 
 // Reads a string with the length as the first two bytes
 inline std::string deSerializeString(std::istream &is)
@@ -1878,15 +1880,17 @@ inline std::string serializeLongString(const std::string plain)
        return s;
 }
 
-// Reads a string with the length as the first four bytes
+/*// Reads a string with the length as the first four bytes
 inline std::string deSerializeLongString(const std::string encoded)
 {
        u32 s_size = readU32((u8*)&encoded.c_str()[0]);
+       if(s_size > encoded.length() - 4)
+               return "";
        std::string s;
        s.reserve(s_size);
-       s.append(&encoded.c_str()[2], s_size);
+       s.append(&encoded.c_str()[4], s_size);
        return s;
-}
+}*/
 
 // Reads a string with the length as the first four bytes
 inline std::string deSerializeLongString(std::istream &is)