Temporary commit; lots of test code and stuff
authorPerttu Ahola <celeron55@gmail.com>
Sun, 20 Feb 2011 22:45:14 +0000 (00:45 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Sun, 20 Feb 2011 22:45:14 +0000 (00:45 +0200)
25 files changed:
data/grass.png
data/stone.png
src/CMakeLists.txt
src/activeobject.h [new file with mode: 0644]
src/client.cpp
src/client.h
src/clientobject.cpp [new file with mode: 0644]
src/clientobject.h [new file with mode: 0644]
src/clientserver.h
src/environment.cpp
src/environment.h
src/jthread/jmutex.h
src/main.cpp
src/map.cpp
src/map.h
src/mapblock.cpp
src/mapblockobject.cpp
src/mapnode.h
src/player.cpp
src/player.h
src/server.cpp
src/server.h
src/serverobject.cpp [new file with mode: 0644]
src/serverobject.h [new file with mode: 0644]
src/utility.h

index 8fe9078caffee8e3a78b9ccd6b70b1782ad8955d..b5c1559f6b9fedf23e48b48eef03524a38bda130 100644 (file)
Binary files a/data/grass.png and b/data/grass.png differ
index c7a453e3f7be95a2dd091542441108ad05b1bca5..d085cb8dd267ade7ae0d8a1e9ac78e0f757acb62 100644 (file)
Binary files a/data/stone.png and b/data/stone.png differ
index c0301cc80cf7c463f151cc891e200be47e35aae8..b26294113ddf2b4cb2dfe09e3afce59c55c5a615 100644 (file)
@@ -50,6 +50,7 @@ configure_file(
 )
 
 set(common_SRCS
+       serverobject.cpp
        noise.cpp
        mineral.cpp
        porting.cpp
@@ -75,8 +76,10 @@ set(common_SRCS
        test.cpp
 )
 
+# Client sources
 set(minetest_SRCS
        ${common_SRCS}
+       clientobject.cpp
        guiMainMenu.cpp
        guiMessageMenu.cpp
        guiTextInputMenu.cpp
@@ -88,6 +91,7 @@ set(minetest_SRCS
        main.cpp
 )
 
+# Server sources
 set(minetestserver_SRCS
        ${common_SRCS}
        servermain.cpp
diff --git a/src/activeobject.h b/src/activeobject.h
new file mode 100644 (file)
index 0000000..103d90d
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef ACTIVEOBJECT_HEADER
+#define ACTIVEOBJECT_HEADER
+
+#include "common_irrlicht.h"
+#include <string>
+
+struct ActiveObjectMessage
+{
+       ActiveObjectMessage(u16 id_, bool reliable_=true, std::string data_=""):
+               id(id_),
+               reliable(reliable_),
+               datastring(data_)
+       {}
+
+       u16 id;
+       bool reliable;
+       std::string datastring;
+};
+
+#define ACTIVEOBJECT_TYPE_INVALID 0
+#define ACTIVEOBJECT_TYPE_TEST 1
+#define ACTIVEOBJECT_TYPE_LUA 2
+
+/*
+       Parent class for ServerActiveObject and ClientActiveObject
+*/
+class ActiveObject
+{
+public:
+       ActiveObject(u16 id):
+               m_id(id)
+       {
+       }
+       
+       u16 getId()
+       {
+               return m_id;
+       }
+
+       void setId(u16 id)
+       {
+               m_id = id;
+       }
+
+       virtual u8 getType() const = 0;
+
+protected:
+       u16 m_id; // 0 is invalid, "no id"
+};
+
+#endif
+
index 21c911ec6fe3eb99ece4e8eed052e4f2df973c11..4ad1f12269548719b055598eedb5f039a18d2537 100644 (file)
@@ -56,10 +56,12 @@ Client::Client(
                const char *playername,
                MapDrawControl &control):
        m_thread(this),
-       m_env(new ClientMap(this, control,
+       m_env(
+               new ClientMap(this, control,
                        device->getSceneManager()->getRootSceneNode(),
                        device->getSceneManager(), 666),
-                       dout_client),
+               device->getSceneManager()
+       ),
        m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
        m_device(device),
        camera_position(0,0,0),
@@ -82,20 +84,25 @@ Client::Client(
        m_step_dtime_mutex.Init();
 
        m_thread.Start();
-       
+
+       /*
+               Add local player
+       */
        {
                JMutexAutoLock envlock(m_env_mutex);
-               //m_env.getMap().StartUpdater();
 
                Player *player = new LocalPlayer();
 
                player->updateName(playername);
 
-               /*f32 y = BS*2 + BS*20;
-               player->setPosition(v3f(0, y, 0));*/
-               //player->setPosition(v3f(0, y, 30900*BS)); // DEBUG
                m_env.addPlayer(player);
        }
+
+       // Add some active objects for testing
+       /*{
+               ClientActiveObject *obj = new TestCAO(0, v3f(0, 10*BS, 0));
+               m_env.addActiveObject(obj);
+       }*/
 }
 
 Client::~Client()
@@ -493,7 +500,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                v3s16 playerpos_s16(0, BS*2+BS*20, 0);
                if(datasize >= 2+1+6)
                        playerpos_s16 = readV3S16(&data[2+1]);
-               v3f playerpos_f = intToFloat(playerpos_s16) - v3f(0, BS/2, 0);
+               v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
 
                { //envlock
                        JMutexAutoLock envlock(m_env_mutex);
@@ -1037,6 +1044,99 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
                
                m_chat_queue.push_back(message);
        }
+       else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
+       {
+               /*
+                       u16 command
+                       u16 count of removed objects
+                       for all removed objects {
+                               u16 id
+                       }
+                       u16 count of added objects
+                       for all added objects {
+                               u16 id
+                               u8 type
+                       }
+               */
+
+               char buf[6];
+               // Get all data except the command number
+               std::string datastring((char*)&data[2], datasize-2);
+               // Throw them in an istringstream
+               std::istringstream is(datastring, std::ios_base::binary);
+
+               // Read stuff
+               
+               // Read removed objects
+               is.read(buf, 2);
+               u16 removed_count = readU16((u8*)buf);
+               for(u16 i=0; i<removed_count; i++)
+               {
+                       is.read(buf, 2);
+                       u16 id = readU16((u8*)buf);
+                       // Remove it
+                       {
+                               JMutexAutoLock envlock(m_env_mutex);
+                               m_env.removeActiveObject(id);
+                       }
+               }
+               
+               // Read added objects
+               is.read(buf, 2);
+               u16 added_count = readU16((u8*)buf);
+               for(u16 i=0; i<added_count; i++)
+               {
+                       is.read(buf, 2);
+                       u16 id = readU16((u8*)buf);
+                       is.read(buf, 1);
+                       u8 type = readU8((u8*)buf);
+                       // Add it
+                       {
+                               JMutexAutoLock envlock(m_env_mutex);
+                               m_env.addActiveObject(id, type);
+                       }
+               }
+       }
+       else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
+       {
+               /*
+                       u16 command
+                       for all objects
+                       {
+                               u16 id
+                               u16 message length
+                               string message
+                       }
+               */
+               char buf[6];
+               // Get all data except the command number
+               std::string datastring((char*)&data[2], datasize-2);
+               // Throw them in an istringstream
+               std::istringstream is(datastring, std::ios_base::binary);
+               
+               while(is.eof() == false)
+               {
+                       // Read stuff
+                       is.read(buf, 2);
+                       u16 id = readU16((u8*)buf);
+                       if(is.eof())
+                               break;
+                       is.read(buf, 2);
+                       u16 message_size = readU16((u8*)buf);
+                       std::string message;
+                       message.reserve(message_size);
+                       for(u16 i=0; i<message_size; i++)
+                       {
+                               is.read(buf, 1);
+                               message.append(buf, 1);
+                       }
+                       // Pass on to the environment
+                       {
+                               JMutexAutoLock envlock(m_env_mutex);
+                               m_env.processActiveObjectMessage(id, message);
+                       }
+               }
+       }
        // Default to queueing it (for slow commands)
        else
        {
@@ -1197,7 +1297,7 @@ bool Client::AsyncProcessPacket()
                        main thread, from which is will want to retrieve textures.
                */
 
-               m_env.getMap().updateMeshes(block->getPos(), getDayNightRatio());
+               m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
        }
        else
        {
@@ -1464,7 +1564,7 @@ void Client::removeNode(v3s16 p)
                        i.atEnd() == false; i++)
        {
                v3s16 p = i.getNode()->getKey();
-               m_env.getMap().updateMeshes(p, m_env.getDayNightRatio());
+               m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
        }
 }
 
@@ -1486,7 +1586,7 @@ void Client::addNode(v3s16 p, MapNode n)
                        i.atEnd() == false; i++)
        {
                v3s16 p = i.getNode()->getKey();
-               m_env.getMap().updateMeshes(p, m_env.getDayNightRatio());
+               m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
        }
 }
        
@@ -1503,36 +1603,6 @@ MapNode Client::getNode(v3s16 p)
        return m_env.getMap().getNode(p);
 }
 
-/*void Client::getNode(v3s16 p, MapNode n)
-{
-       JMutexAutoLock envlock(m_env_mutex);
-       m_env.getMap().setNode(p, n);
-}*/
-
-/*f32 Client::getGroundHeight(v2s16 p)
-{
-       JMutexAutoLock envlock(m_env_mutex);
-       return m_env.getMap().getGroundHeight(p);
-}*/
-
-/*bool Client::isNodeUnderground(v3s16 p)
-{
-       JMutexAutoLock envlock(m_env_mutex);
-       return m_env.getMap().isNodeUnderground(p);
-}*/
-
-/*Player * Client::getLocalPlayer()
-{
-       JMutexAutoLock envlock(m_env_mutex);
-       return m_env.getLocalPlayer();
-}*/
-
-/*core::list<Player*> Client::getPlayers()
-{
-       JMutexAutoLock envlock(m_env_mutex);
-       return m_env.getPlayers();
-}*/
-
 v3f Client::getPlayerPosition()
 {
        JMutexAutoLock envlock(m_env_mutex);
@@ -1597,7 +1667,7 @@ MapBlockObject * Client::getSelectedObject(
 
                // Calculate from_pos relative to block
                v3s16 block_pos_i_on_map = block->getPosRelative();
-               v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map);
+               v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
                v3f from_pos_f_on_block = from_pos_f_on_map - block_pos_f_on_map;
 
                block->getObjects(from_pos_f_on_block, max_d, objects);
@@ -1617,7 +1687,7 @@ MapBlockObject * Client::getSelectedObject(
 
                // Calculate shootline relative to block
                v3s16 block_pos_i_on_map = block->getPosRelative();
-               v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map);
+               v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
                core::line3d<f32> shootline_on_block(
                                shootline_on_map.start - block_pos_f_on_map,
                                shootline_on_map.end - block_pos_f_on_map
@@ -1672,7 +1742,7 @@ u32 Client::getDayNightRatio()
        v3f playerpos = player->getPosition();
        v3f playerspeed = player->getSpeed();
 
-       v3s16 center_nodepos = floatToInt(playerpos);
+       v3s16 center_nodepos = floatToInt(playerpos, BS);
        v3s16 center = getNodeBlockPos(center_nodepos);
 
        u32 counter = 0;
index 00fd3a5edf72476735083fd7111e3a0bd8b841de..fb1e70722e1a936cf8c96d88c8cda2099f01b8e3 100644 (file)
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "common_irrlicht.h"
 #include "jmutex.h"
 #include <ostream>
+#include "clientobject.h"
 
 class ClientNotReadyException : public BaseException
 {
@@ -165,11 +166,6 @@ public:
        
        // Returns InvalidPositionException if not found
        MapNode getNode(v3s16 p);
-       // Returns InvalidPositionException if not found
-       //void setNode(v3s16 p, MapNode n);
-
-       // Returns InvalidPositionException if not found
-       //f32 getGroundHeight(v2s16 p);
 
        v3f getPlayerPosition();
 
@@ -192,7 +188,6 @@ public:
        // Prints a line or two of info
        void printDebugInfo(std::ostream &os);
 
-       //s32 getDayNightIndex();
        u32 getDayNightRatio();
 
        //void updateSomeExpiredMeshes();
@@ -230,27 +225,6 @@ public:
                }
        }
 
-#if 0
-       void setTempMod(v3s16 p, NodeMod mod)
-       {
-               JMutexAutoLock envlock(m_env_mutex);
-               assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
-               bool changed = false;
-               v3s16 blockpos = ((ClientMap&)m_env.getMap()).setTempMod(p, mod, &changed);
-               if(changed)
-                       m_env.getMap().updateMeshes(blockpos, m_env.getDayNightRatio());
-       }
-       void clearTempMod(v3s16 p)
-       {
-               JMutexAutoLock envlock(m_env_mutex);
-               assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
-               bool changed = false;
-               v3s16 blockpos = ((ClientMap&)m_env.getMap()).clearTempMod(p, &changed);
-               if(changed)
-                       m_env.getMap().updateMeshes(blockpos, m_env.getDayNightRatio());
-       }
-#endif
-
        float getAvgRtt()
        {
                JMutexAutoLock lock(m_con_mutex);
@@ -302,15 +276,12 @@ private:
        // NOTE: If connection and environment are both to be locked,
        // environment shall be locked first.
 
-       Environment m_env;
+       ClientEnvironment m_env;
        JMutex m_env_mutex;
        
        con::Connection m_con;
        JMutex m_con_mutex;
 
-       /*core::map<v3s16, float> m_fetchblock_history;
-       JMutex m_fetchblock_mutex;*/
-
        core::list<IncomingPacket> m_incoming_queue;
        JMutex m_incoming_queue_mutex;
 
diff --git a/src/clientobject.cpp b/src/clientobject.cpp
new file mode 100644 (file)
index 0000000..46db389
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "clientobject.h"
+#include "debug.h"
+#include "porting.h"
+#include "constants.h"
+#include "utility.h"
+
+ClientActiveObject::ClientActiveObject(u16 id):
+       ActiveObject(id)
+{
+}
+
+ClientActiveObject::~ClientActiveObject()
+{
+       removeFromScene();
+}
+
+ClientActiveObject* ClientActiveObject::create(u8 type)
+{
+       if(type == ACTIVEOBJECT_TYPE_INVALID)
+       {
+               dstream<<"ClientActiveObject::create(): passed "
+                               <<"ACTIVEOBJECT_TYPE_INVALID"<<std::endl;
+               return NULL;
+       }
+       else if(type == ACTIVEOBJECT_TYPE_TEST)
+       {
+               dstream<<"ClientActiveObject::create(): passed "
+                               <<"ACTIVEOBJECT_TYPE_TEST"<<std::endl;
+               return new TestCAO(0);
+       }
+       else if(type == ACTIVEOBJECT_TYPE_LUA)
+       {
+               dstream<<"ClientActiveObject::create(): passed "
+                               <<"ACTIVEOBJECT_TYPE_LUA"<<std::endl;
+               return NULL;
+       }
+       else
+       {
+               dstream<<"ClientActiveObject::create(): passed "
+                               <<"unknown type="<<type<<std::endl;
+               return NULL;
+       }
+}
+
+/*
+       TestCAO
+*/
+
+TestCAO::TestCAO(u16 id):
+       ClientActiveObject(id),
+       m_node(NULL),
+       m_position(v3f(0,10*BS,0))
+{
+}
+
+TestCAO::~TestCAO()
+{
+}
+
+void TestCAO::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,-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),
+       };
+       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(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();
+       updateNodePos();
+}
+
+void TestCAO::removeFromScene()
+{
+       if(m_node == NULL)
+               return;
+
+       m_node->remove();
+       m_node = NULL;
+}
+
+void TestCAO::updateLight(u8 light_at_pos)
+{
+}
+
+v3s16 TestCAO::getLightPosition()
+{
+       return floatToInt(m_position, BS);
+}
+
+void TestCAO::updateNodePos()
+{
+       if(m_node == NULL)
+               return;
+
+       m_node->setPosition(m_position);
+       //m_node->setRotation(v3f(0, 45, 0));
+}
+
+void TestCAO::step(float dtime)
+{
+       if(m_node)
+       {
+               v3f rot = m_node->getRotation();
+               //dstream<<"dtime="<<dtime<<", rot.Y="<<rot.Y<<std::endl;
+               rot.Y += dtime * 180;
+               m_node->setRotation(rot);
+       }
+}
+
+void TestCAO::processMessage(const std::string &data)
+{
+       //dstream<<"TestCAO: Got data: "<<data<<std::endl;
+       std::istringstream is(data, std::ios::binary);
+       u16 cmd;
+       is>>cmd;
+       if(cmd == 0)
+       {
+               v3f newpos;
+               is>>newpos.X;
+               is>>newpos.Y;
+               is>>newpos.Z;
+               m_position = newpos;
+               updateNodePos();
+       }
+}
+
+
diff --git a/src/clientobject.h b/src/clientobject.h
new file mode 100644 (file)
index 0000000..454531a
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef CLIENTOBJECT_HEADER
+#define CLIENTOBJECT_HEADER
+
+#include "common_irrlicht.h"
+#include "activeobject.h"
+
+/*
+
+Some planning
+-------------
+
+* Client receives a network packet with information of added objects
+  in it
+* Client supplies the information to its ClientEnvironment
+* The environment adds the specified objects to itself
+
+*/
+
+class ClientActiveObject : public ActiveObject
+{
+public:
+       ClientActiveObject(u16 id);
+       virtual ~ClientActiveObject();
+
+       virtual void addToScene(scene::ISceneManager *smgr){}
+       virtual void removeFromScene(){}
+       // 0 <= light_at_pos <= LIGHT_SUN
+       virtual void updateLight(u8 light_at_pos){}
+       virtual v3s16 getLightPosition(){return v3s16(0,0,0);}
+       
+       // Step object in time
+       virtual void step(float dtime){}
+       
+       // Process a message sent by the server side object
+       virtual void processMessage(const std::string &data){}
+
+       static ClientActiveObject* create(u8 type);
+
+protected:
+};
+
+class TestCAO : public ClientActiveObject
+{
+public:
+       TestCAO(u16 id);
+       virtual ~TestCAO();
+       
+       u8 getType() const
+       {
+               return ACTIVEOBJECT_TYPE_TEST;
+       }
+       
+       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);
+
+private:
+       scene::IMeshSceneNode *m_node;
+       v3f m_position;
+};
+
+#endif
+
index 07b1cf60f317daa3fc0e90174b08afec6c920995..66ee58473e5a83e2c069d09fd75600f426dc4368 100644 (file)
@@ -106,6 +106,31 @@ enum ToClientCommand
                wstring message
        */
 
+       TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD = 0x31,
+       /*
+               u16 command
+               u16 count of removed objects
+               for all removed objects {
+                       u16 id
+               }
+               u16 count of added objects
+               for all added objects {
+                       u16 id
+                       u8 type
+               }
+       */
+       
+       TOCLIENT_ACTIVE_OBJECT_MESSAGES = 0x32,
+       /*
+               u16 command
+               for all objects
+               {
+                       u16 id
+                       u16 message length
+                       string message
+               }
+       */
+
 };
 
 enum ToServerCommand
index 07437ec400057dc175d60622eea739812c7c4699..5e16602e0712956ec1fb0bcaac829206452941c8 100644 (file)
@@ -20,11 +20,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "environment.h"
 #include "filesys.h"
 
-Environment::Environment(Map *map, std::ostream &dout):
-               m_dout(dout)
+Environment::Environment()
 {
-       m_map = map;
-       m_daynight_ratio = 0.2;
+       m_daynight_ratio = 0.5;
 }
 
 Environment::~Environment()
@@ -35,183 +33,16 @@ Environment::~Environment()
        {
                delete (*i);
        }
-       
-       // The map is removed by the SceneManager
-       m_map->drop();
-       //delete m_map;
-}
-
-void Environment::step(float dtime)
-{
-       DSTACK(__FUNCTION_NAME);
-       /*
-               Run Map's timers
-       */
-       //TimeTaker maptimerupdatetimer("m_map->timerUpdate()", g_device);
-       // 0ms
-       m_map->timerUpdate(dtime);
-       //maptimerupdatetimer.stop();
-
-       /*
-               Get the highest speed some player is going
-       */
-       //TimeTaker playerspeed("playerspeed", g_device);
-       // 0ms
-       f32 maximum_player_speed = 0.001; // just some small value
-       for(core::list<Player*>::Iterator i = m_players.begin();
-                       i != m_players.end(); i++)
-       {
-               f32 speed = (*i)->getSpeed().getLength();
-               if(speed > maximum_player_speed)
-                       maximum_player_speed = speed;
-       }
-       //playerspeed.stop();
-       
-       /*
-               Maximum position increment
-       */
-       //f32 position_max_increment = 0.05*BS;
-       f32 position_max_increment = 0.1*BS;
-
-       // Maximum time increment (for collision detection etc)
-       // time = distance / speed
-       f32 dtime_max_increment = position_max_increment / maximum_player_speed;
-       // Maximum time increment is 10ms or lower
-       if(dtime_max_increment > 0.01)
-               dtime_max_increment = 0.01;
-       
-       //TimeTaker playerupdate("playerupdate", g_device);
-       
-       /*
-               Stuff that has a maximum time increment
-       */
-       // Don't allow overly huge dtime
-       if(dtime > 0.5)
-               dtime = 0.5;
-
-       u32 loopcount = 0;
-       do
-       {
-               loopcount++;
-
-               f32 dtime_part;
-               if(dtime > dtime_max_increment)
-                       dtime_part = dtime_max_increment;
-               else
-                       dtime_part = dtime;
-               dtime -= dtime_part;
-               
-               /*
-                       Handle players
-               */
-               for(core::list<Player*>::Iterator i = m_players.begin();
-                               i != m_players.end(); i++)
-               {
-                       Player *player = *i;
-
-                       v3f playerpos = player->getPosition();
-                       
-                       // Apply physics to local player
-                       bool free_move = g_settings.getBool("free_move");
-                       if(player->isLocal() && free_move == false)
-                       {
-                               // Apply gravity to local player
-                               v3f speed = player->getSpeed();
-                               if(player->swimming_up == false)
-                                       speed.Y -= 9.81 * BS * dtime_part * 2;
-
-                               /*
-                                       Apply water resistance
-                               */
-                               if(player->in_water_stable || player->in_water)
-                               {
-                                       f32 max_down = 2.0*BS;
-                                       if(speed.Y < -max_down) speed.Y = -max_down;
-
-                                       f32 max = 2.5*BS;
-                                       if(speed.getLength() > max)
-                                       {
-                                               speed = speed / speed.getLength() * max;
-                                       }
-                               }
-
-                               player->setSpeed(speed);
-                       }
-
-                       /*
-                               Move the player.
-                               For local player, this also calculates collision detection.
-                       */
-                       player->move(dtime_part, *m_map, position_max_increment);
-                       
-                       /*
-                               Update lighting on remote players on client
-                       */
-                       u8 light = LIGHT_MAX;
-                       try{
-                               // Get node at feet
-                               v3s16 p = floatToInt(playerpos + v3f(0,BS/4,0));
-                               MapNode n = m_map->getNode(p);
-                               light = n.getLightBlend(m_daynight_ratio);
-                       }
-                       catch(InvalidPositionException &e) {}
-                       player->updateLight(light);
-
-                       /*
-                               Add footsteps to grass
-                       */
-                       if(g_settings.getBool("footprints"))
-                       {
-                               // Get node that is at BS/4 under player
-                               v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0));
-                               try{
-                                       MapNode n = m_map->getNode(bottompos);
-                                       if(n.d == CONTENT_GRASS)
-                                       {
-                                               n.d = CONTENT_GRASS_FOOTSTEPS;
-                                               m_map->setNode(bottompos, n);
-#ifndef SERVER
-                                               // Update mesh on client
-                                               if(m_map->mapType() == MAPTYPE_CLIENT)
-                                               {
-                                                       v3s16 p_blocks = getNodeBlockPos(bottompos);
-                                                       MapBlock *b = m_map->getBlockNoCreate(p_blocks);
-                                                       b->updateMesh(m_daynight_ratio);
-                                               }
-#endif
-                                       }
-                               }
-                               catch(InvalidPositionException &e)
-                               {
-                               }
-                       }
-               }
-       }
-       while(dtime > 0.001);
-       
-       //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
-}
-
-Map & Environment::getMap()
-{
-       return *m_map;
 }
 
 void Environment::addPlayer(Player *player)
 {
        DSTACK(__FUNCTION_NAME);
        /*
-               Check that only one local player exists and peer_ids are unique.
+               Check that peer_ids are unique.
                Also check that names are unique.
                Exception: there can be multiple players with peer_id=0
        */
-#ifndef SERVER
-       /*
-               It is a failure if player is local and there already is a local
-               player
-       */
-       assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
-#endif
        // If peer id is non-zero, it has to be unique.
        if(player->peer_id != 0)
                assert(getPlayer(player->peer_id) == NULL);
@@ -240,20 +71,6 @@ re_search:
        }
 }
 
-#ifndef SERVER
-LocalPlayer * Environment::getLocalPlayer()
-{
-       for(core::list<Player*>::Iterator i = m_players.begin();
-                       i != m_players.end(); i++)
-       {
-               Player *player = *i;
-               if(player->isLocal())
-                       return (LocalPlayer*)player;
-       }
-       return NULL;
-}
-#endif
-
 Player * Environment::getPlayer(u16 peer_id)
 {
        for(core::list<Player*>::Iterator i = m_players.begin();
@@ -315,7 +132,38 @@ void Environment::printPlayers(std::ostream &o)
        }
 }
 
-void Environment::serializePlayers(const std::string &savedir)
+void Environment::setDayNightRatio(u32 r)
+{
+       m_daynight_ratio = r;
+}
+
+u32 Environment::getDayNightRatio()
+{
+       return m_daynight_ratio;
+}
+
+/*
+       ServerEnvironment
+*/
+
+ServerEnvironment::ServerEnvironment(ServerMap *map):
+       m_map(map),
+       m_random_spawn_timer(0)
+{
+       /*
+               TEST CODE
+       */
+       TestSAO *obj = new TestSAO(0, v3f(0, BS*5, 0));
+       addActiveObject(obj);
+}
+
+ServerEnvironment::~ServerEnvironment()
+{
+       // Drop/delete map
+       m_map->drop();
+}
+
+void ServerEnvironment::serializePlayers(const std::string &savedir)
 {
        std::string players_path = savedir + "/players";
        fs::CreateDir(players_path);
@@ -430,7 +278,7 @@ void Environment::serializePlayers(const std::string &savedir)
        //dstream<<"Saved "<<saved_players.size()<<" players."<<std::endl;
 }
 
-void Environment::deSerializePlayers(const std::string &savedir)
+void ServerEnvironment::deSerializePlayers(const std::string &savedir)
 {
        std::string players_path = savedir + "/players";
 
@@ -492,25 +340,630 @@ void Environment::deSerializePlayers(const std::string &savedir)
        }
 }
 
+void ServerEnvironment::step(float dtime)
+{
+       DSTACK(__FUNCTION_NAME);
+
+       // Get some settings
+       //bool free_move = g_settings.getBool("free_move");
+       bool footprints = g_settings.getBool("footprints");
+
+       {
+               //TimeTaker timer("Server m_map->timerUpdate()", g_device);
+               m_map->timerUpdate(dtime);
+       }
+
+       /*
+               Handle players
+       */
+       for(core::list<Player*>::Iterator i = m_players.begin();
+                       i != m_players.end(); i++)
+       {
+               Player *player = *i;
+               v3f playerpos = player->getPosition();
+               
+               // Move
+               player->move(dtime, *m_map, 100*BS);
+               
+               /*
+                       Add footsteps to grass
+               */
+               if(footprints)
+               {
+                       // Get node that is at BS/4 under player
+                       v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
+                       try{
+                               MapNode n = m_map->getNode(bottompos);
+                               if(n.d == CONTENT_GRASS)
+                               {
+                                       n.d = CONTENT_GRASS_FOOTSTEPS;
+                                       m_map->setNode(bottompos, n);
+                               }
+                       }
+                       catch(InvalidPositionException &e)
+                       {
+                       }
+               }
+       }
+       
+       /*
+               Step active objects
+       */
+       for(core::map<u16, ServerActiveObject*>::Iterator
+                       i = m_active_objects.getIterator();
+                       i.atEnd()==false; i++)
+       {
+               ServerActiveObject* obj = i.getNode()->getValue();
+               // Step object, putting messages directly to the queue
+               obj->step(dtime, m_active_object_messages);
+       }
+
+       /*
+               Remove (m_removed && m_known_by_count==0) objects
+       */
+       {
+               core::list<u16> objects_to_remove;
+               for(core::map<u16, ServerActiveObject*>::Iterator
+                               i = m_active_objects.getIterator();
+                               i.atEnd()==false; i++)
+               {
+                       u16 id = i.getNode()->getKey();
+                       ServerActiveObject* obj = i.getNode()->getValue();
+                       // This shouldn't happen but check it
+                       if(obj == NULL)
+                       {
+                               dstream<<"WARNING: NULL object found in ServerEnvironment"
+                                               <<" while finding removed objects. id="<<id<<std::endl;
+                               // Id to be removed from m_active_objects
+                               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);
+               }
+       }
+
+       /*
+               TEST CODE
+       */
+       m_random_spawn_timer -= dtime;
+       if(m_random_spawn_timer < 0)
+       {
+               m_random_spawn_timer += 0.1;
+               TestSAO *obj = new TestSAO(0,
+                               v3f(myrand_range(-2*BS,2*BS), BS*5, myrand_range(-2*BS,2*BS)));
+               addActiveObject(obj);
+       }
+}
+
+ServerActiveObject* ServerEnvironment::getActiveObject(u16 id)
+{
+       core::map<u16, ServerActiveObject*>::Node *n;
+       n = m_active_objects.find(id);
+       if(n == NULL)
+               return NULL;
+       return n->getValue();
+}
+
+bool isFreeServerActiveObjectId(u16 id,
+               core::map<u16, ServerActiveObject*> &objects)
+{
+       if(id == 0)
+               return false;
+       
+       for(core::map<u16, ServerActiveObject*>::Iterator
+                       i = objects.getIterator();
+                       i.atEnd()==false; i++)
+       {
+               if(i.getNode()->getKey() == id)
+                       return false;
+       }
+       return true;
+}
+
+u16 getFreeServerActiveObjectId(
+               core::map<u16, ServerActiveObject*> &objects)
+{
+       u16 new_id = 1;
+       for(;;)
+       {
+               if(isFreeServerActiveObjectId(new_id, objects))
+                       return new_id;
+               
+               if(new_id == 65535)
+                       return 0;
+
+               new_id++;
+       }
+}
+
+u16 ServerEnvironment::addActiveObject(ServerActiveObject *object)
+{
+       assert(object);
+       if(object->getId() == 0)
+       {
+               u16 new_id = getFreeServerActiveObjectId(m_active_objects);
+               if(new_id == 0)
+               {
+                       dstream<<"WARNING: ServerEnvironment::addActiveObject(): "
+                                       <<"no free ids available"<<std::endl;
+                       delete object;
+                       return 0;
+               }
+               object->setId(new_id);
+       }
+       if(isFreeServerActiveObjectId(object->getId(), m_active_objects) == false)
+       {
+               dstream<<"WARNING: ServerEnvironment::addActiveObject(): "
+                               <<"id is not free ("<<object->getId()<<")"<<std::endl;
+               delete object;
+               return 0;
+       }
+       dstream<<"INGO: ServerEnvironment::addActiveObject(): "
+                       <<"added (id="<<object->getId()<<")"<<std::endl;
+       m_active_objects.insert(object->getId(), object);
+       return object->getId();
+}
+
+/*
+       Finds out what new objects have been added to
+       inside a radius around a position
+*/
+void ServerEnvironment::getAddedActiveObjects(v3s16 pos, s16 radius,
+               core::map<u16, bool> &current_objects,
+               core::map<u16, bool> &added_objects)
+{
+       v3f pos_f = intToFloat(pos, BS);
+       f32 radius_f = radius * BS;
+       /*
+               Go through the object list,
+               - discard m_removed objects,
+               - discard objects that are too far away,
+               - discard objects that are found in current_objects.
+               - add remaining objects to added_objects
+       */
+       for(core::map<u16, ServerActiveObject*>::Iterator
+                       i = m_active_objects.getIterator();
+                       i.atEnd()==false; i++)
+       {
+               u16 id = i.getNode()->getKey();
+               // Get object
+               ServerActiveObject *object = i.getNode()->getValue();
+               if(object == NULL)
+                       continue;
+               // Discard if removed
+               if(object->m_removed)
+                       continue;
+               // Discard if too far
+               f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
+               if(distance_f > radius_f)
+                       continue;
+               // Discard if already on current_objects
+               core::map<u16, bool>::Node *n;
+               n = current_objects.find(id);
+               if(n != NULL)
+                       continue;
+               // Add to added_objects
+               added_objects.insert(id, false);
+       }
+}
+
+/*
+       Finds out what objects have been removed from
+       inside a radius around a position
+*/
+void ServerEnvironment::getRemovedActiveObjects(v3s16 pos, s16 radius,
+               core::map<u16, bool> &current_objects,
+               core::map<u16, bool> &removed_objects)
+{
+       v3f pos_f = intToFloat(pos, BS);
+       f32 radius_f = radius * BS;
+       /*
+               Go through current_objects; object is removed if:
+               - object is not found in m_active_objects (this is actually an
+                 error condition; objects should be set m_removed=true and removed
+                 only after all clients have been informed about removal), or
+               - object has m_removed=true, or
+               - object is too far away
+       */
+       for(core::map<u16, bool>::Iterator
+                       i = current_objects.getIterator();
+                       i.atEnd()==false; i++)
+       {
+               u16 id = i.getNode()->getKey();
+               ServerActiveObject *object = getActiveObject(id);
+               if(object == NULL)
+               {
+                       dstream<<"WARNING: ServerEnvironment::getRemovedActiveObjects():"
+                                       <<" object in current_objects is NULL"<<std::endl;
+               }
+               else if(object->m_removed == false)
+               {
+                       f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f);
+                       /*dstream<<"removed == false"
+                                       <<"distance_f = "<<distance_f
+                                       <<", radius_f = "<<radius_f<<std::endl;*/
+                       if(distance_f < radius_f)
+                       {
+                               // Not removed
+                               continue;
+                       }
+               }
+               removed_objects.insert(id, false);
+       }
+}
+
+ActiveObjectMessage ServerEnvironment::getActiveObjectMessage()
+{
+       if(m_active_object_messages.size() == 0)
+               return ActiveObjectMessage(0);
+       
+       return m_active_object_messages.pop_front();
+}
+
 #ifndef SERVER
-void Environment::updateMeshes(v3s16 blockpos)
+
+/*
+       ClientEnvironment
+*/
+
+ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr):
+       m_map(map),
+       m_smgr(smgr)
+{
+       assert(m_map);
+       assert(m_smgr);
+}
+
+ClientEnvironment::~ClientEnvironment()
+{
+       // delete active objects
+       for(core::map<u16, ClientActiveObject*>::Iterator
+                       i = m_active_objects.getIterator();
+                       i.atEnd()==false; i++)
+       {
+               delete i.getNode()->getValue();
+       }
+
+       // Drop/delete map
+       m_map->drop();
+}
+
+void ClientEnvironment::addPlayer(Player *player)
+{
+       DSTACK(__FUNCTION_NAME);
+       /*
+               It is a failure if player is local and there already is a local
+               player
+       */
+       assert(!(player->isLocal() == true && getLocalPlayer() != NULL));
+
+       Environment::addPlayer(player);
+}
+
+LocalPlayer * ClientEnvironment::getLocalPlayer()
+{
+       for(core::list<Player*>::Iterator i = m_players.begin();
+                       i != m_players.end(); i++)
+       {
+               Player *player = *i;
+               if(player->isLocal())
+                       return (LocalPlayer*)player;
+       }
+       return NULL;
+}
+
+void ClientEnvironment::step(float dtime)
+{
+       DSTACK(__FUNCTION_NAME);
+
+       // Get some settings
+       bool free_move = g_settings.getBool("free_move");
+       bool footprints = g_settings.getBool("footprints");
+
+       {
+               //TimeTaker timer("Client m_map->timerUpdate()", g_device);
+               m_map->timerUpdate(dtime);
+       }
+
+       /*
+               Get the speed the player is going
+       */
+       f32 player_speed = 0.001; // just some small value
+       LocalPlayer *lplayer = getLocalPlayer();
+       if(lplayer)
+               player_speed = lplayer->getSpeed().getLength();
+       
+       /*
+               Maximum position increment
+       */
+       //f32 position_max_increment = 0.05*BS;
+       f32 position_max_increment = 0.1*BS;
+
+       // Maximum time increment (for collision detection etc)
+       // time = distance / speed
+       f32 dtime_max_increment = position_max_increment / player_speed;
+       
+       // Maximum time increment is 10ms or lower
+       if(dtime_max_increment > 0.01)
+               dtime_max_increment = 0.01;
+       
+       // Don't allow overly huge dtime
+       if(dtime > 0.5)
+               dtime = 0.5;
+       
+       f32 dtime_downcount = dtime;
+
+       /*
+               Stuff that has a maximum time increment
+       */
+
+       u32 loopcount = 0;
+       do
+       {
+               loopcount++;
+
+               f32 dtime_part;
+               if(dtime_downcount > dtime_max_increment)
+                       dtime_part = dtime_max_increment;
+               else
+                       dtime_part = dtime;
+               dtime_downcount -= dtime_part;
+               
+               /*
+                       Handle local player
+               */
+               
+               {
+                       Player *player = getLocalPlayer();
+
+                       v3f playerpos = player->getPosition();
+                       
+                       // Apply physics
+                       if(free_move == false)
+                       {
+                               // Gravity
+                               v3f speed = player->getSpeed();
+                               if(player->swimming_up == false)
+                                       speed.Y -= 9.81 * BS * dtime_part * 2;
+
+                               // Water resistance
+                               if(player->in_water_stable || player->in_water)
+                               {
+                                       f32 max_down = 2.0*BS;
+                                       if(speed.Y < -max_down) speed.Y = -max_down;
+
+                                       f32 max = 2.5*BS;
+                                       if(speed.getLength() > max)
+                                       {
+                                               speed = speed / speed.getLength() * max;
+                                       }
+                               }
+
+                               player->setSpeed(speed);
+                       }
+
+                       /*
+                               Move the player.
+                               This also does collision detection.
+                       */
+                       player->move(dtime_part, *m_map, position_max_increment);
+               }
+       }
+       while(dtime_downcount > 0.001);
+               
+       //std::cout<<"Looped "<<loopcount<<" times."<<std::endl;
+       
+       /*
+               Stuff that can be done in an arbitarily large dtime
+       */
+       for(core::list<Player*>::Iterator i = m_players.begin();
+                       i != m_players.end(); i++)
+       {
+               Player *player = *i;
+               v3f playerpos = player->getPosition();
+               
+               /*
+                       Handle non-local players
+               */
+               if(player->isLocal() == false)
+               {
+                       // Move
+                       player->move(dtime, *m_map, 100*BS);
+
+                       // Update lighting on remote players on client
+                       u8 light = LIGHT_MAX;
+                       try{
+                               // Get node at head
+                               v3s16 p = floatToInt(playerpos + v3f(0,BS+BS/2,0), BS);
+                               MapNode n = m_map->getNode(p);
+                               light = n.getLightBlend(m_daynight_ratio);
+                       }
+                       catch(InvalidPositionException &e) {}
+                       player->updateLight(light);
+               }
+               
+               /*
+                       Add footsteps to grass
+               */
+               if(footprints)
+               {
+                       // Get node that is at BS/4 under player
+                       v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
+                       try{
+                               MapNode n = m_map->getNode(bottompos);
+                               if(n.d == CONTENT_GRASS)
+                               {
+                                       n.d = CONTENT_GRASS_FOOTSTEPS;
+                                       m_map->setNode(bottompos, n);
+                                       // Update mesh on client
+                                       if(m_map->mapType() == MAPTYPE_CLIENT)
+                                       {
+                                               v3s16 p_blocks = getNodeBlockPos(bottompos);
+                                               MapBlock *b = m_map->getBlockNoCreate(p_blocks);
+                                               b->updateMesh(m_daynight_ratio);
+                                       }
+                               }
+                       }
+                       catch(InvalidPositionException &e)
+                       {
+                       }
+               }
+       }
+       
+       /*
+               Step active objects
+       */
+       for(core::map<u16, ClientActiveObject*>::Iterator
+                       i = m_active_objects.getIterator();
+                       i.atEnd()==false; i++)
+       {
+               ClientActiveObject* obj = i.getNode()->getValue();
+               // Step object
+               obj->step(dtime);
+       }
+}
+
+void ClientEnvironment::updateMeshes(v3s16 blockpos)
 {
        m_map->updateMeshes(blockpos, m_daynight_ratio);
 }
 
-void Environment::expireMeshes(bool only_daynight_diffed)
+void ClientEnvironment::expireMeshes(bool only_daynight_diffed)
 {
        m_map->expireMeshes(only_daynight_diffed);
 }
-#endif
 
-void Environment::setDayNightRatio(u32 r)
+ClientActiveObject* ClientEnvironment::getActiveObject(u16 id)
 {
-       m_daynight_ratio = r;
+       core::map<u16, ClientActiveObject*>::Node *n;
+       n = m_active_objects.find(id);
+       if(n == NULL)
+               return NULL;
+       return n->getValue();
 }
 
-u32 Environment::getDayNightRatio()
+bool isFreeClientActiveObjectId(u16 id,
+               core::map<u16, ClientActiveObject*> &objects)
 {
-       return m_daynight_ratio;
+       if(id == 0)
+               return false;
+       
+       for(core::map<u16, ClientActiveObject*>::Iterator
+                       i = objects.getIterator();
+                       i.atEnd()==false; i++)
+       {
+               if(i.getNode()->getKey() == id)
+                       return false;
+       }
+       return true;
+}
+
+u16 getFreeClientActiveObjectId(
+               core::map<u16, ClientActiveObject*> &objects)
+{
+       u16 new_id = 1;
+       for(;;)
+       {
+               if(isFreeClientActiveObjectId(new_id, objects))
+                       return new_id;
+               
+               if(new_id == 65535)
+                       return 0;
+
+               new_id++;
+       }
 }
 
+u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
+{
+       assert(object);
+       if(object->getId() == 0)
+       {
+               u16 new_id = getFreeClientActiveObjectId(m_active_objects);
+               if(new_id == 0)
+               {
+                       dstream<<"WARNING: ClientEnvironment::addActiveObject(): "
+                                       <<"no free ids available"<<std::endl;
+                       delete object;
+                       return 0;
+               }
+               object->setId(new_id);
+       }
+       if(isFreeClientActiveObjectId(object->getId(), m_active_objects) == false)
+       {
+               dstream<<"WARNING: ClientEnvironment::addActiveObject(): "
+                               <<"id is not free ("<<object->getId()<<")"<<std::endl;
+               delete object;
+               return 0;
+       }
+       dstream<<"INGO: ClientEnvironment::addActiveObject(): "
+                       <<"added (id="<<object->getId()<<")"<<std::endl;
+       m_active_objects.insert(object->getId(), object);
+       object->addToScene(m_smgr);
+       return object->getId();
+}
+
+void ClientEnvironment::addActiveObject(u16 id, u8 type)
+{
+       ClientActiveObject* obj = ClientActiveObject::create(type);
+       if(obj == NULL)
+       {
+               dstream<<"WARNING: ClientEnvironment::addActiveObject(): "
+                               <<"id="<<id<<" type="<<type<<": Couldn't create object"
+                               <<std::endl;
+               return;
+       }
+       
+       obj->setId(id);
+
+       addActiveObject(obj);
+}
+
+void ClientEnvironment::removeActiveObject(u16 id)
+{
+       dstream<<"ClientEnvironment::removeActiveObject(): "
+                       <<"id="<<id<<std::endl;
+       ClientActiveObject* obj = getActiveObject(id);
+       if(obj == NULL)
+       {
+               dstream<<"WARNING: ClientEnvironment::removeActiveObject(): "
+                               <<"id="<<id<<" not found"<<std::endl;
+               return;
+       }
+       obj->removeFromScene();
+       delete obj;
+       m_active_objects.remove(id);
+}
+
+void ClientEnvironment::processActiveObjectMessage(u16 id,
+               const std::string &data)
+{
+       ClientActiveObject* obj = getActiveObject(id);
+       if(obj == NULL)
+       {
+               dstream<<"WARNING: ClientEnvironment::processActiveObjectMessage():"
+                               <<" got message for id="<<id<<", which doesn't exist."
+                               <<std::endl;
+               return;
+       }
+       obj->processMessage(data);
+}
+
+#endif // #ifndef SERVER
+
+
index dfc60673b66698c1b1bc82ff47301079b97cdd66..1a786af23e7a5538c2a33320c1fde85a6f6e0e9f 100644 (file)
@@ -26,7 +26,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
        - The map
        - Players
        - Other objects
-       - The current time in the game, etc.
+       - The current time in the game (actually it only contains the brightness)
+       - etc.
 */
 
 #include <list>
@@ -39,51 +40,175 @@ class Environment
 {
 public:
        // Environment will delete the map passed to the constructor
-       Environment(Map *map, std::ostream &dout);
-       ~Environment();
+       Environment();
+       virtual ~Environment();
+
        /*
-               This can do anything to the environment, such as removing
-               timed-out players.
-               Also updates Map's timers.
+               Step everything in environment.
+               - Move players
+               - Step mobs
+               - Run timers of map
        */
-       void step(f32 dtime);
+       virtual void step(f32 dtime) = 0;
 
-       Map & getMap();
+       virtual Map & getMap() = 0;
 
-       /*
-               Environment deallocates players after use.
-       */
-       void addPlayer(Player *player);
+       virtual void addPlayer(Player *player);
        void removePlayer(u16 peer_id);
-#ifndef SERVER
-       LocalPlayer * getLocalPlayer();
-#endif
        Player * getPlayer(u16 peer_id);
        Player * getPlayer(const char *name);
        core::list<Player*> getPlayers();
        core::list<Player*> getPlayers(bool ignore_disconnected);
        void printPlayers(std::ostream &o);
        
+       void setDayNightRatio(u32 r);
+       u32 getDayNightRatio();
+
+protected:
+       // peer_ids in here should be unique, except that there may be many 0s
+       core::list<Player*> m_players;
+       // Brightness
+       u32 m_daynight_ratio;
+};
+
+/*
+       The server-side environment.
+
+       This is not thread-safe. Server uses an environment mutex.
+*/
+
+#include "serverobject.h"
+
+class ServerEnvironment : public Environment
+{
+public:
+       ServerEnvironment(ServerMap *map);
+       ~ServerEnvironment();
+
+       Map & getMap()
+       {
+               return *m_map;
+       }
+
+       ServerMap & getServerMap()
+       {
+               return *m_map;
+       }
+
+       void step(f32 dtime);
+
        void serializePlayers(const std::string &savedir);
-       // This loads players as ServerRemotePlayers
        void deSerializePlayers(const std::string &savedir);
 
+       /*
+               ActiveObjects
+       */
+
+       ServerActiveObject* getActiveObject(u16 id);
+
+       /*
+               Adds an active object to the environment.
+               Environment handles deletion of object.
+               Object may be deleted by environment immediately.
+               If id of object is 0, assigns a free id to it.
+               Returns the id of the object.
+               Returns 0 if not added and thus deleted.
+       */
+       u16 addActiveObject(ServerActiveObject *object);
+       
+       /*
+               Finds out what new objects have been added to
+               inside a radius around a position
+       */
+       void getAddedActiveObjects(v3s16 pos, s16 radius,
+                       core::map<u16, bool> &current_objects,
+                       core::map<u16, bool> &added_objects);
+
+       /*
+               Finds out what new objects have been removed from
+               inside a radius around a position
+       */
+       void getRemovedActiveObjects(v3s16 pos, s16 radius,
+                       core::map<u16, bool> &current_objects,
+                       core::map<u16, bool> &removed_objects);
+       
+       /*
+               Gets the next message emitted by some active object.
+               Returns a message with id=0 if no messages are available.
+       */
+       ActiveObjectMessage getActiveObjectMessage();
+       
+private:
+       ServerMap *m_map;
+       core::map<u16, ServerActiveObject*> m_active_objects;
+       Queue<ActiveObjectMessage> m_active_object_messages;
+       float m_random_spawn_timer;
+};
+
 #ifndef SERVER
+
+#include "clientobject.h"
+
+/*
+       The client-side environment.
+
+       This is not thread-safe.
+       Must be called from main (irrlicht) thread (uses the SceneManager)
+       Client uses an environment mutex.
+*/
+
+class ClientEnvironment : public Environment
+{
+public:
+       ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr);
+       ~ClientEnvironment();
+
+       Map & getMap()
+       {
+               return *m_map;
+       }
+
+       ClientMap & getClientMap()
+       {
+               return *m_map;
+       }
+
+       void step(f32 dtime);
+
+       virtual void addPlayer(Player *player);
+       LocalPlayer * getLocalPlayer();
+
        void updateMeshes(v3s16 blockpos);
        void expireMeshes(bool only_daynight_diffed);
-#endif
-       void setDayNightRatio(u32 r);
-       u32 getDayNightRatio();
+
+       /*
+               ActiveObjects
+       */
+       
+       ClientActiveObject* getActiveObject(u16 id);
+
+       /*
+               Adds an active object to the environment.
+               Environment handles deletion of object.
+               Object may be deleted by environment immediately.
+               If id of object is 0, assigns a free id to it.
+               Returns the id of the object.
+               Returns 0 if not added and thus deleted.
+       */
+       u16 addActiveObject(ClientActiveObject *object);
+
+       void addActiveObject(u16 id, u8 type);
+       void removeActiveObject(u16 id);
+
+       void processActiveObjectMessage(u16 id, const std::string &data);
 
 private:
-       Map *m_map;
-       // peer_ids in here should be unique, except that there may be
-       // many 0s
-       core::list<Player*> m_players;
-       // Debug output goes here
-       std::ostream &m_dout;
-       u32 m_daynight_ratio;
+       ClientMap *m_map;
+       scene::ISceneManager *m_smgr;
+       core::map<u16, ClientActiveObject*> m_active_objects;
 };
 
 #endif
 
+#endif
+
index 39bd95f02281318aaad2b557d1feabb67da74fd6..9ce013096f8a3817417d079003f2ed8319b15d5a 100644 (file)
@@ -35,7 +35,7 @@
        #endif // _WIN32_WCE
        #include <winsock2.h>
        #include <windows.h>
-       
+       // CriticalSection is way faster than the alternative
        #define JMUTEX_CRITICALSECTION
 #else // using pthread
        #include <pthread.h>
index 2754c324b930cf7fe36644d036e45f3684bc30fc..f0bc6d7a249578abb2038ea40f029b73dbcc8b3a 100644 (file)
@@ -160,32 +160,23 @@ TODO: Make fetching sector's blocks more efficient when rendering
 \r
 TODO: Flowing water animation\r
 \r
-NOTE(FIXED): A lock condition is possible:\r
-       1) MapBlock::updateMesh() is called from client asynchronously:\r
-          - AsyncProcessData() -> Map::updateMeshes()\r
-       2) Asynchronous locks m_temp_mods_mutex\r
-       3) MapBlock::updateMesh() is called from client synchronously:\r
-          - Client::step() -> Environment::step()\r
-       4) Synchronous starts waiting for m_temp_mods_mutex\r
-       5) Asynchronous calls getTexture, which starts waiting for main thread\r
-\r
 Configuration:\r
 --------------\r
 \r
-TODO: Make the video backend selectable\r
-\r
 Client:\r
 -------\r
 \r
 TODO: Untie client network operations from framerate\r
       - Needs some input queues or something\r
 \r
-TODO: Make morning and evening transition more smooth and maybe shorter\r
+SUGG: Make morning and evening transition more smooth and maybe shorter\r
 \r
-TODO: Don't update all meshes always on single node changes, but\r
+SUGG: Don't update all meshes always on single node changes, but\r
       check which ones should be updated\r
          - implement Map::updateNodeMeshes()\r
 \r
+TODO: Remove IrrlichtWrapper\r
+\r
 Server:\r
 -------\r
 \r
@@ -194,16 +185,13 @@ TODO: When player dies, throw items on map
 TODO: Make an option to the server to disable building and digging near\r
       the starting position\r
 \r
-TODO: Save players with inventories to disk\r
-TODO: Players to be saved as text in map/players/<name>\r
-\r
 TODO: Copy the text of the last picked sign to inventory in creative\r
       mode\r
 \r
 TODO: Check what goes wrong with caching map to disk (Kray)\r
       - Nothing?\r
 \r
-TODO: When server sees that client is removing an inexistent block to\r
+TODO: When server sees that client is removing an inexistent block in\r
       an existent position, resend the MapBlock.\r
 \r
 FIXME: Server went into some infinite PeerNotFoundException loop\r
@@ -237,6 +225,11 @@ Block object server side:
            - TODO: For incoming blocks, time difference is calculated and\r
              objects are stepped according to it.\r
 \r
+- When an active object goes far from a player, either delete\r
+  it or store it statically.\r
+- When a statically stored active object comes near a player,\r
+  recreate the active object\r
+\r
 Map:\r
 ----\r
 \r
@@ -345,18 +338,18 @@ Doing now (most important at the top):
 #include <fstream>\r
 #include <jmutexautolock.h>\r
 #include <locale.h>\r
+#include "main.h"\r
 #include "common_irrlicht.h"\r
 #include "debug.h"\r
 #include "map.h"\r
 #include "player.h"\r
-#include "main.h"\r
 #include "test.h"\r
-#include "environment.h"\r
+//#include "environment.h"\r
 #include "server.h"\r
 #include "client.h"\r
-#include "serialization.h"\r
+//#include "serialization.h"\r
 #include "constants.h"\r
-#include "strfnd.h"\r
+//#include "strfnd.h"\r
 #include "porting.h"\r
 #include "irrlichtwrapper.h"\r
 #include "gettime.h"\r
@@ -905,8 +898,12 @@ class RandomInputHandler : public InputHandler
 public:\r
        RandomInputHandler()\r
        {\r
+               leftdown = false;\r
+               rightdown = false;\r
                leftclicked = false;\r
                rightclicked = false;\r
+               leftreleased = false;\r
+               rightreleased = false;\r
                for(u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)\r
                        keydown[i] = false;\r
        }\r
@@ -925,11 +922,11 @@ public:
 \r
        virtual bool getLeftState()\r
        {\r
-               return false;\r
+               return leftdown;\r
        }\r
        virtual bool getRightState()\r
        {\r
-               return false;\r
+               return rightdown;\r
        }\r
 \r
        virtual bool getLeftClicked()\r
@@ -951,37 +948,23 @@ public:
 \r
        virtual bool getLeftReleased()\r
        {\r
-               return false;\r
+               return leftreleased;\r
        }\r
        virtual bool getRightReleased()\r
        {\r
-               return false;\r
+               return rightreleased;\r
        }\r
        virtual void resetLeftReleased()\r
        {\r
+               leftreleased = false;\r
        }\r
        virtual void resetRightReleased()\r
        {\r
+               rightreleased = false;\r
        }\r
 \r
        virtual void step(float dtime)\r
        {\r
-               {\r
-                       static float counter1 = 0;\r
-                       counter1 -= dtime;\r
-                       if(counter1 < 0.0)\r
-                       {\r
-                               counter1 = 0.1*Rand(1,10);\r
-                               /*if(g_selected_material < USEFUL_CONTENT_COUNT-1)\r
-                                       g_selected_material++;\r
-                               else\r
-                                       g_selected_material = 0;*/\r
-                               if(g_selected_item < PLAYER_INVENTORY_SIZE-1)\r
-                                       g_selected_item++;\r
-                               else\r
-                                       g_selected_item = 0;\r
-                       }\r
-               }\r
                {\r
                        static float counter1 = 0;\r
                        counter1 -= dtime;\r
@@ -1033,7 +1016,11 @@ public:
                        if(counter1 < 0.0)\r
                        {\r
                                counter1 = 0.1*Rand(1, 30);\r
-                               leftclicked = true;\r
+                               leftdown = !leftdown;\r
+                               if(leftdown)\r
+                                       leftclicked = true;\r
+                               if(!leftdown)\r
+                                       leftreleased = true;\r
                        }\r
                }\r
                {\r
@@ -1041,8 +1028,12 @@ public:
                        counter1 -= dtime;\r
                        if(counter1 < 0.0)\r
                        {\r
-                               counter1 = 0.1*Rand(1, 20);\r
-                               rightclicked = true;\r
+                               counter1 = 0.1*Rand(1, 15);\r
+                               rightdown = !rightdown;\r
+                               if(rightdown)\r
+                                       rightclicked = true;\r
+                               if(!rightdown)\r
+                                       rightreleased = true;\r
                        }\r
                }\r
                mousepos += mousespeed;\r
@@ -1056,8 +1047,12 @@ private:
        bool keydown[KEY_KEY_CODES_COUNT];\r
        v2s32 mousepos;\r
        v2s32 mousespeed;\r
+       bool leftdown;\r
+       bool rightdown;\r
        bool leftclicked;\r
        bool rightclicked;\r
+       bool leftreleased;\r
+       bool rightreleased;\r
 };\r
 \r
 void updateViewingRange(f32 frametime_in, Client *client)\r
@@ -2486,11 +2481,9 @@ int main(int argc, char *argv[])
                camera->setTarget(camera_position + camera_direction * 100.0);\r
 \r
                if(FIELD_OF_VIEW_TEST){\r
-                       //client.m_env.getMap().updateCamera(v3f(0,0,0), v3f(0,0,1));\r
                        client.updateCamera(v3f(0,0,0), v3f(0,0,1));\r
                }\r
                else{\r
-                       //client.m_env.getMap().updateCamera(camera_position, camera_direction);\r
                        //TimeTaker timer("client.updateCamera");\r
                        client.updateCamera(camera_position, camera_direction);\r
                }\r
@@ -2585,7 +2578,7 @@ int main(int argc, char *argv[])
                core::aabbox3d<f32> nodehilightbox;\r
                f32 mindistance = BS * 1001;\r
                \r
-               v3s16 pos_i = floatToInt(player_position);\r
+               v3s16 pos_i = floatToInt(player_position, BS);\r
 \r
                /*std::cout<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"\r
                                <<std::endl;*/\r
@@ -2615,7 +2608,7 @@ int main(int argc, char *argv[])
                        }\r
 \r
                        v3s16 np(x,y,z);\r
-                       v3f npf = intToFloat(np);\r
+                       v3f npf = intToFloat(np, BS);\r
                        \r
                        f32 d = 0.01;\r
                        \r
@@ -2723,7 +2716,7 @@ int main(int argc, char *argv[])
                                                        const float d = 0.502;\r
                                                        core::aabbox3d<f32> nodebox\r
                                                                        (-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);\r
-                                                       v3f nodepos_f = intToFloat(nodepos);\r
+                                                       v3f nodepos_f = intToFloat(nodepos, BS);\r
                                                        nodebox.MinEdge += nodepos_f;\r
                                                        nodebox.MaxEdge += nodepos_f;\r
                                                        nodehilightbox = nodebox;\r
index 159682696b0b1a792b88c489f53d16460771afcf..c92039664dca79cf2fdfb2297f731ae9c5e5de02 100644 (file)
@@ -1221,95 +1221,6 @@ void Map::removeNodeAndUpdate(v3s16 p,
        }
 }
 
-#ifndef SERVER
-void Map::expireMeshes(bool only_daynight_diffed)
-{
-       TimeTaker timer("expireMeshes()");
-
-       core::map<v2s16, MapSector*>::Iterator si;
-       si = m_sectors.getIterator();
-       for(; si.atEnd() == false; si++)
-       {
-               MapSector *sector = si.getNode()->getValue();
-
-               core::list< MapBlock * > sectorblocks;
-               sector->getBlocks(sectorblocks);
-               
-               core::list< MapBlock * >::Iterator i;
-               for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
-               {
-                       MapBlock *block = *i;
-
-                       if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
-                       {
-                               continue;
-                       }
-                       
-                       {
-                               JMutexAutoLock lock(block->mesh_mutex);
-                               if(block->mesh != NULL)
-                               {
-                                       /*block->mesh->drop();
-                                       block->mesh = NULL;*/
-                                       block->setMeshExpired(true);
-                               }
-                       }
-               }
-       }
-}
-
-void Map::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
-{
-       assert(mapType() == MAPTYPE_CLIENT);
-
-       try{
-               v3s16 p = blockpos + v3s16(0,0,0);
-               MapBlock *b = getBlockNoCreate(p);
-               b->updateMesh(daynight_ratio);
-       }
-       catch(InvalidPositionException &e){}
-       // Leading edge
-       try{
-               v3s16 p = blockpos + v3s16(-1,0,0);
-               MapBlock *b = getBlockNoCreate(p);
-               b->updateMesh(daynight_ratio);
-       }
-       catch(InvalidPositionException &e){}
-       try{
-               v3s16 p = blockpos + v3s16(0,-1,0);
-               MapBlock *b = getBlockNoCreate(p);
-               b->updateMesh(daynight_ratio);
-       }
-       catch(InvalidPositionException &e){}
-       try{
-               v3s16 p = blockpos + v3s16(0,0,-1);
-               MapBlock *b = getBlockNoCreate(p);
-               b->updateMesh(daynight_ratio);
-       }
-       catch(InvalidPositionException &e){}
-       /*// Trailing edge
-       try{
-               v3s16 p = blockpos + v3s16(1,0,0);
-               MapBlock *b = getBlockNoCreate(p);
-               b->updateMesh(daynight_ratio);
-       }
-       catch(InvalidPositionException &e){}
-       try{
-               v3s16 p = blockpos + v3s16(0,1,0);
-               MapBlock *b = getBlockNoCreate(p);
-               b->updateMesh(daynight_ratio);
-       }
-       catch(InvalidPositionException &e){}
-       try{
-               v3s16 p = blockpos + v3s16(0,0,1);
-               MapBlock *b = getBlockNoCreate(p);
-               b->updateMesh(daynight_ratio);
-       }
-       catch(InvalidPositionException &e){}*/
-}
-
-#endif
-
 bool Map::dayNightDiffed(v3s16 blockpos)
 {
        try{
@@ -4371,7 +4282,7 @@ continue_generating:
                        //if(!is_ground_content(block->getNode(cp).d))
                        if(1)
                        {
-                               RatObject *obj = new RatObject(NULL, -1, intToFloat(cp));
+                               RatObject *obj = new RatObject(NULL, -1, intToFloat(cp, BS));
                                block->addObject(obj);
                        }
                }
@@ -5667,6 +5578,92 @@ bool ClientMap::clearTempMod(v3s16 p,
        return changed;
 }
 
+void ClientMap::expireMeshes(bool only_daynight_diffed)
+{
+       TimeTaker timer("expireMeshes()");
+
+       core::map<v2s16, MapSector*>::Iterator si;
+       si = m_sectors.getIterator();
+       for(; si.atEnd() == false; si++)
+       {
+               MapSector *sector = si.getNode()->getValue();
+
+               core::list< MapBlock * > sectorblocks;
+               sector->getBlocks(sectorblocks);
+               
+               core::list< MapBlock * >::Iterator i;
+               for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
+               {
+                       MapBlock *block = *i;
+
+                       if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
+                       {
+                               continue;
+                       }
+                       
+                       {
+                               JMutexAutoLock lock(block->mesh_mutex);
+                               if(block->mesh != NULL)
+                               {
+                                       /*block->mesh->drop();
+                                       block->mesh = NULL;*/
+                                       block->setMeshExpired(true);
+                               }
+                       }
+               }
+       }
+}
+
+void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
+{
+       assert(mapType() == MAPTYPE_CLIENT);
+
+       try{
+               v3s16 p = blockpos + v3s16(0,0,0);
+               MapBlock *b = getBlockNoCreate(p);
+               b->updateMesh(daynight_ratio);
+       }
+       catch(InvalidPositionException &e){}
+       // Leading edge
+       try{
+               v3s16 p = blockpos + v3s16(-1,0,0);
+               MapBlock *b = getBlockNoCreate(p);
+               b->updateMesh(daynight_ratio);
+       }
+       catch(InvalidPositionException &e){}
+       try{
+               v3s16 p = blockpos + v3s16(0,-1,0);
+               MapBlock *b = getBlockNoCreate(p);
+               b->updateMesh(daynight_ratio);
+       }
+       catch(InvalidPositionException &e){}
+       try{
+               v3s16 p = blockpos + v3s16(0,0,-1);
+               MapBlock *b = getBlockNoCreate(p);
+               b->updateMesh(daynight_ratio);
+       }
+       catch(InvalidPositionException &e){}
+       /*// Trailing edge
+       try{
+               v3s16 p = blockpos + v3s16(1,0,0);
+               MapBlock *b = getBlockNoCreate(p);
+               b->updateMesh(daynight_ratio);
+       }
+       catch(InvalidPositionException &e){}
+       try{
+               v3s16 p = blockpos + v3s16(0,1,0);
+               MapBlock *b = getBlockNoCreate(p);
+               b->updateMesh(daynight_ratio);
+       }
+       catch(InvalidPositionException &e){}
+       try{
+               v3s16 p = blockpos + v3s16(0,0,1);
+               MapBlock *b = getBlockNoCreate(p);
+               b->updateMesh(daynight_ratio);
+       }
+       catch(InvalidPositionException &e){}*/
+}
+
 void ClientMap::PrintInfo(std::ostream &out)
 {
        out<<"ClientMap: ";
index 60cfd698b76c2f686368d4617f57e5798cf9fcc4..adff82db06e6fcb43ab23ea73bbd8a24d9d27947 100644 (file)
--- a/src/map.h
+++ b/src/map.h
@@ -33,7 +33,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #endif
 
 #include "common_irrlicht.h"
-//#include "heightmap.h"
 #include "mapnode.h"
 #include "mapblock.h"
 #include "mapsector.h"
@@ -61,7 +60,10 @@ public:
        {
                return MAPTYPE_BASE;
        }
-
+       
+       /*
+               Drop (client) or delete (server) the map.
+       */
        virtual void drop()
        {
                delete this;
@@ -211,19 +213,6 @@ public:
        void removeNodeAndUpdate(v3s16 p,
                        core::map<v3s16, MapBlock*> &modified_blocks);
        
-#ifndef SERVER
-       void expireMeshes(bool only_daynight_diffed);
-       
-       /*
-               Update the faces of the given block and blocks on the
-               leading edge.
-       */
-       void updateMeshes(v3s16 blockpos, u32 daynight_ratio);
-       
-       // Update meshes that touch the node
-       //void updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio);
-#endif
-
        /*
                Takes the blocks at the edges into account
        */
@@ -628,6 +617,17 @@ public:
        // Efficient implementation needs a cache of TempMods
        //void clearTempMods();
 
+       void expireMeshes(bool only_daynight_diffed);
+       
+       /*
+               Update the faces of the given block and blocks on the
+               leading edge.
+       */
+       void updateMeshes(v3s16 blockpos, u32 daynight_ratio);
+       
+       // Update meshes that touch the node
+       //void updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio);
+
        // For debug printing
        virtual void PrintInfo(std::ostream &out);
        
index a1e3c6694c5138b2d378677d1e11f0b7d2677472..d489ec8ac11d47137c7ddc60e93bec895d5e464f 100644 (file)
@@ -822,7 +822,7 @@ void MapBlock::updateMesh(u32 daynight_ratio)
                                if(dir == v3s16(0,1,0))
                                        vertices[i].Pos.rotateXZBy(-45);
 
-                               vertices[i].Pos += intToFloat(p + getPosRelative());
+                               vertices[i].Pos += intToFloat(p + getPosRelative(), BS);
                        }
 
                        // Set material
@@ -1066,7 +1066,7 @@ void MapBlock::updateMesh(u32 daynight_ratio)
                                        if(dir == v3s16(1,0,-0))
                                                vertices[j].Pos.rotateXZBy(-90);
 
-                                       vertices[j].Pos += intToFloat(p + getPosRelative());
+                                       vertices[j].Pos += intToFloat(p + getPosRelative(), BS);
                                }
 
                                u16 indices[] = {0,1,2,2,3,0};
@@ -1105,7 +1105,7 @@ void MapBlock::updateMesh(u32 daynight_ratio)
                                        //vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
                                        s32 j = corner_resolve[i];
                                        vertices[i].Pos.Y += corner_levels[j];
-                                       vertices[i].Pos += intToFloat(p + getPosRelative());
+                                       vertices[i].Pos += intToFloat(p + getPosRelative(), BS);
                                }
 
                                u16 indices[] = {0,1,2,2,3,0};
@@ -1155,7 +1155,7 @@ void MapBlock::updateMesh(u32 daynight_ratio)
                        for(s32 i=0; i<4; i++)
                        {
                                vertices[i].Pos.Y += (-0.5+node_water_level)*BS;
-                               vertices[i].Pos += intToFloat(p + getPosRelative());
+                               vertices[i].Pos += intToFloat(p + getPosRelative(), BS);
                        }
 
                        u16 indices[] = {0,1,2,2,3,0};
@@ -1222,7 +1222,7 @@ void MapBlock::updateMesh(u32 daynight_ratio)
 
                                for(u16 i=0; i<4; i++)
                                {
-                                       vertices[i].Pos += intToFloat(p + getPosRelative());
+                                       vertices[i].Pos += intToFloat(p + getPosRelative(), BS);
                                }
 
                                u16 indices[] = {0,1,2,2,3,0};
@@ -1596,7 +1596,7 @@ void MapBlock::stepObjects(float dtime, bool server, u32 daynight_ratio)
                                if(getNode(p).d == CONTENT_AIR
                                                && getNode(p).getLightBlend(daynight_ratio) <= 11)
                                {
-                                       RatObject *obj = new RatObject(NULL, -1, intToFloat(p));
+                                       RatObject *obj = new RatObject(NULL, -1, intToFloat(p, BS));
                                        addObject(obj);
                                }
                        }
index ab12afc8e12a75aad035c6524668ea843551167c..ff58fd04555a4e29c0a24ce65d26ea0fee12067e 100644 (file)
@@ -35,7 +35,7 @@ v3f MapBlockObject::getAbsolutePos()
                return m_pos;
        
        // getPosRelative gets nodepos relative to map origin
-       v3f blockpos = intToFloat(m_block->getPosRelative());
+       v3f blockpos = intToFloat(m_block->getPosRelative(), BS);
        return blockpos + m_pos;
 }
 
@@ -55,7 +55,7 @@ v3f MovingObject::getAbsoluteShowPos()
                return m_pos;
        
        // getPosRelative gets nodepos relative to map origin
-       v3f blockpos = intToFloat(m_block->getPosRelative());
+       v3f blockpos = intToFloat(m_block->getPosRelative(), BS);
        return blockpos + m_showpos;
 }
 
@@ -71,7 +71,7 @@ void MovingObject::move(float dtime, v3f acceleration)
                        acceleration.X, acceleration.Y, acceleration.Z
                        );
        
-       v3s16 oldpos_i = floatToInt(m_pos);
+       v3s16 oldpos_i = floatToInt(m_pos, BS);
        
        if(m_block->isValidPosition(oldpos_i) == false)
        {
@@ -137,7 +137,7 @@ void MovingObject::move(float dtime, v3f acceleration)
                        Collision detection
                */
                
-               v3s16 pos_i = floatToInt(position);
+               v3s16 pos_i = floatToInt(position, BS);
                
                // The loop length is limited to the object moving a distance
                f32 d = (float)BS * 0.15;
@@ -614,7 +614,7 @@ void MapBlockObjectList::update(std::istream &is, u8 version,
                {
                        u8 light = LIGHT_MAX;
                        try{
-                               v3s16 relpos_i = floatToInt(obj->m_pos);
+                               v3s16 relpos_i = floatToInt(obj->m_pos, BS);
                                MapNode n = m_block->getNodeParent(relpos_i);
                                light = n.getLightBlend(daynight_ratio);
                        }
@@ -772,7 +772,7 @@ void MapBlockObjectList::step(float dtime, bool server, u32 daynight_ratio)
                                // Update light
                                u8 light = LIGHT_MAX;
                                try{
-                                       v3s16 relpos_i = floatToInt(obj->m_pos);
+                                       v3s16 relpos_i = floatToInt(obj->m_pos, BS);
                                        MapNode n = m_block->getNodeParent(relpos_i);
                                        light = n.getLightBlend(daynight_ratio);
                                }
@@ -824,7 +824,7 @@ void MapBlockObjectList::step(float dtime, bool server, u32 daynight_ratio)
                {
                        MapBlockObject *obj = i.getNode()->getValue();
 
-                       v3s16 pos_i = floatToInt(obj->m_pos);
+                       v3s16 pos_i = floatToInt(obj->m_pos, BS);
 
                        if(m_block->isValidPosition(pos_i))
                        {
@@ -871,7 +871,7 @@ bool MapBlockObjectList::wrapObject(MapBlockObject *object)
        // Calculate blockpos on map
        v3s16 oldblock_pos_i_on_map = m_block->getPosRelative();
        v3f pos_f_on_oldblock = object->m_pos;
-       v3s16 pos_i_on_oldblock = floatToInt(pos_f_on_oldblock);
+       v3s16 pos_i_on_oldblock = floatToInt(pos_f_on_oldblock, BS);
        v3s16 pos_i_on_map = pos_i_on_oldblock + oldblock_pos_i_on_map;
        v3s16 pos_blocks_on_map = getNodeBlockPos(pos_i_on_map);
 
@@ -905,9 +905,9 @@ bool MapBlockObjectList::wrapObject(MapBlockObject *object)
        }
        
        // Calculate position on new block
-       v3f oldblock_pos_f_on_map = intToFloat(oldblock_pos_i_on_map);
+       v3f oldblock_pos_f_on_map = intToFloat(oldblock_pos_i_on_map, BS);
        v3s16 newblock_pos_i_on_map = newblock->getPosRelative();
-       v3f newblock_pos_f_on_map = intToFloat(newblock_pos_i_on_map);
+       v3f newblock_pos_f_on_map = intToFloat(newblock_pos_i_on_map, BS);
        v3f pos_f_on_newblock = pos_f_on_oldblock
                        - newblock_pos_f_on_map + oldblock_pos_f_on_map;
 
index d67b9629e56ed8b27400662a64e1539bd0334fd1..7819d701d03e26fee322f2543ac4afc111be6a5b 100644 (file)
@@ -683,32 +683,6 @@ struct MapNode
        }
 };
 
-/*
-       Returns integer position of the node in given
-       floating point position.
-*/
-inline v3s16 floatToInt(v3f p)
-{
-       v3s16 p2(
-               (p.X + (p.X>0 ? BS/2 : -BS/2))/BS,
-               (p.Y + (p.Y>0 ? BS/2 : -BS/2))/BS,
-               (p.Z + (p.Z>0 ? BS/2 : -BS/2))/BS);
-       return p2;
-}
-
-/*
-       The same thing backwards
-*/
-inline v3f intToFloat(v3s16 p)
-{
-       v3f p2(
-               p.X * BS,
-               p.Y * BS,
-               p.Z * BS
-       );
-       return p2;
-}
-
 
 
 #endif
index 9f8a97e7f12a65cfdd234b6415e12fa7b60f402f..07879c21adafdcfb113cef2a865ce4b2d23fd076 100644 (file)
@@ -273,7 +273,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
 {
        v3f position = getPosition();
        v3f oldpos = position;
-       v3s16 oldpos_i = floatToInt(oldpos);
+       v3s16 oldpos_i = floatToInt(oldpos, BS);
 
        /*std::cout<<"oldpos_i=("<<oldpos_i.X<<","<<oldpos_i.Y<<","
                        <<oldpos_i.Z<<")"<<std::endl;*/
@@ -296,7 +296,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
        */
        
        // Player position in nodes
-       v3s16 pos_i = floatToInt(position);
+       v3s16 pos_i = floatToInt(position, BS);
        
        /*
                Check if player is in water (the oscillating value)
@@ -305,13 +305,13 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
                // If in water, the threshold of coming out is at higher y
                if(in_water)
                {
-                       v3s16 pp = floatToInt(position + v3f(0,BS*0.1,0));
+                       v3s16 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
                        in_water = content_liquid(map.getNode(pp).d);
                }
                // If not in water, the threshold of going in is at lower y
                else
                {
-                       v3s16 pp = floatToInt(position + v3f(0,BS*0.5,0));
+                       v3s16 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
                        in_water = content_liquid(map.getNode(pp).d);
                }
        }
@@ -324,7 +324,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
                Check if player is in water (the stable value)
        */
        try{
-               v3s16 pp = floatToInt(position + v3f(0,0,0));
+               v3s16 pp = floatToInt(position + v3f(0,0,0), BS);
                in_water_stable = content_liquid(map.getNode(pp).d);
        }
        catch(InvalidPositionException &e)
@@ -363,7 +363,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
        if(control.sneak && m_sneak_node_exists)
        {
                f32 maxd = 0.5*BS + sneak_max;
-               v3f lwn_f = intToFloat(m_sneak_node);
+               v3f lwn_f = intToFloat(m_sneak_node, BS);
                position.X = rangelim(position.X, lwn_f.X-maxd, lwn_f.X+maxd);
                position.Z = rangelim(position.Z, lwn_f.Z-maxd, lwn_f.Z+maxd);
                
@@ -537,13 +537,13 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
                player is sneaking from, if any.
        */
        {
-               v3s16 pos_i_bottom = floatToInt(position - v3f(0,BS/2,0));
+               v3s16 pos_i_bottom = floatToInt(position - v3f(0,BS/2,0), BS);
                v2f player_p2df(position.X, position.Z);
                f32 min_distance_f = 100000.0*BS;
                // If already seeking from some node, compare to it.
                /*if(m_sneak_node_exists)
                {
-                       v3f sneaknode_pf = intToFloat(m_sneak_node);
+                       v3f sneaknode_pf = intToFloat(m_sneak_node, BS);
                        v2f sneaknode_p2df(sneaknode_pf.X, sneaknode_pf.Z);
                        f32 d_horiz_f = player_p2df.getDistanceFrom(sneaknode_p2df);
                        f32 d_vert_f = fabs(sneaknode_pf.Y + BS*0.5 - position.Y);
@@ -556,7 +556,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d)
                for(s16 z=-1; z<=1; z++)
                {
                        v3s16 p = pos_i_bottom + v3s16(x,0,z);
-                       v3f pf = intToFloat(p);
+                       v3f pf = intToFloat(p, BS);
                        v2f node_p2df(pf.X, pf.Z);
                        f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
                        f32 max_axis_distance_f = MYMAX(
index 16de6c924ef3fd567bbd56fe50e6315f4ae42723..710a9e0ed7c61bffc17385e4e1b869bcce3b45e7 100644 (file)
@@ -132,6 +132,10 @@ protected:
        v3f m_position;
 };
 
+/*
+       Player on the server
+*/
+
 class ServerRemotePlayer : public Player
 {
 public:
@@ -150,12 +154,16 @@ public:
        virtual void move(f32 dtime, Map &map, f32 pos_max_d)
        {
        }
-
+       
 private:
 };
 
 #ifndef SERVER
 
+/*
+       All the other players on the client are these
+*/
+
 class RemotePlayer : public Player, public scene::ISceneNode
 {
 public:
index 26d0d5d75f98c4401ed5adcf926ec5d468cb1429..6f04ef33a6ec2055e6c322ba5099ea616b73c8b7 100644 (file)
@@ -283,21 +283,14 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
        DSTACK(__FUNCTION_NAME);
        
        // Increment timers
-       {
-               JMutexAutoLock lock(m_blocks_sent_mutex);
-               m_nearest_unsent_reset_timer += dtime;
-       }
+       m_nearest_unsent_reset_timer += dtime;
 
        // Won't send anything if already sending
+       if(m_blocks_sending.size() >= g_settings.getU16
+                       ("max_simultaneous_block_sends_per_client"))
        {
-               JMutexAutoLock lock(m_blocks_sending_mutex);
-               
-               if(m_blocks_sending.size() >= g_settings.getU16
-                               ("max_simultaneous_block_sends_per_client"))
-               {
-                       //dstream<<"Not sending any blocks, Queue full."<<std::endl;
-                       return;
-               }
+               //dstream<<"Not sending any blocks, Queue full."<<std::endl;
+               return;
        }
 
        Player *player = server->m_env.getPlayer(peer_id);
@@ -307,7 +300,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
        v3f playerpos = player->getPosition();
        v3f playerspeed = player->getSpeed();
 
-       v3s16 center_nodepos = floatToInt(playerpos);
+       v3s16 center_nodepos = floatToInt(playerpos, BS);
 
        v3s16 center = getNodeBlockPos(center_nodepos);
        
@@ -323,29 +316,26 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
        */
        s16 last_nearest_unsent_d;
        s16 d_start;
-       {
-               JMutexAutoLock lock(m_blocks_sent_mutex);
                
-               if(m_last_center != center)
-               {
-                       m_nearest_unsent_d = 0;
-                       m_last_center = center;
-               }
-
-               /*dstream<<"m_nearest_unsent_reset_timer="
-                               <<m_nearest_unsent_reset_timer<<std::endl;*/
-               if(m_nearest_unsent_reset_timer > 5.0)
-               {
-                       m_nearest_unsent_reset_timer = 0;
-                       m_nearest_unsent_d = 0;
-                       //dstream<<"Resetting m_nearest_unsent_d"<<std::endl;
-               }
+       if(m_last_center != center)
+       {
+               m_nearest_unsent_d = 0;
+               m_last_center = center;
+       }
 
-               last_nearest_unsent_d = m_nearest_unsent_d;
-               
-               d_start = m_nearest_unsent_d;
+       /*dstream<<"m_nearest_unsent_reset_timer="
+                       <<m_nearest_unsent_reset_timer<<std::endl;*/
+       if(m_nearest_unsent_reset_timer > 5.0)
+       {
+               m_nearest_unsent_reset_timer = 0;
+               m_nearest_unsent_d = 0;
+               //dstream<<"Resetting m_nearest_unsent_d"<<std::endl;
        }
 
+       last_nearest_unsent_d = m_nearest_unsent_d;
+       
+       d_start = m_nearest_unsent_d;
+
        u16 maximum_simultaneous_block_sends_setting = g_settings.getU16
                        ("max_simultaneous_block_sends_per_client");
        u16 maximum_simultaneous_block_sends = 
@@ -356,24 +346,15 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                
                Decrease send rate if player is building stuff.
        */
+       m_time_from_building += dtime;
+       if(m_time_from_building < g_settings.getFloat(
+                               "full_block_send_enable_min_time_from_building"))
        {
-               SharedPtr<JMutexAutoLock> lock(m_time_from_building.getLock());
-               m_time_from_building.m_value += dtime;
-               /*if(m_time_from_building.m_value
-                               < FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING)*/
-               if(m_time_from_building.m_value < g_settings.getFloat(
-                                       "full_block_send_enable_min_time_from_building"))
-               {
-                       maximum_simultaneous_block_sends
-                               = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
-               }
+               maximum_simultaneous_block_sends
+                       = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
        }
        
-       u32 num_blocks_selected;
-       {
-               JMutexAutoLock lock(m_blocks_sending_mutex);
-               num_blocks_selected = m_blocks_sending.size();
-       }
+       u32 num_blocks_selected = m_blocks_sending.size();
        
        /*
                next time d will be continued from the d from which the nearest
@@ -384,11 +365,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
        */
        s32 new_nearest_unsent_d = -1;
 
-       // Serialization version used
-       //u8 ser_version = serialization_version;
-
-       //bool has_incomplete_blocks = false;
-       
        s16 d_max = g_settings.getS16("max_block_send_distance");
        s16 d_max_gen = g_settings.getS16("max_block_generate_distance");
        
@@ -398,20 +374,16 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
        {
                //dstream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
                
-               //if(has_incomplete_blocks == false)
+               /*
+                       If m_nearest_unsent_d was changed by the EmergeThread
+                       (it can change it to 0 through SetBlockNotSent),
+                       update our d to it.
+                       Else update m_nearest_unsent_d
+               */
+               if(m_nearest_unsent_d != last_nearest_unsent_d)
                {
-                       JMutexAutoLock lock(m_blocks_sent_mutex);
-                       /*
-                               If m_nearest_unsent_d was changed by the EmergeThread
-                               (it can change it to 0 through SetBlockNotSent),
-                               update our d to it.
-                               Else update m_nearest_unsent_d
-                       */
-                       if(m_nearest_unsent_d != last_nearest_unsent_d)
-                       {
-                               d = m_nearest_unsent_d;
-                               last_nearest_unsent_d = m_nearest_unsent_d;
-                       }
+                       d = m_nearest_unsent_d;
+                       last_nearest_unsent_d = m_nearest_unsent_d;
                }
 
                /*
@@ -443,23 +415,19 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                                                maximum_simultaneous_block_sends_setting;
                        }
 
+                       // Limit is dynamically lowered when building
+                       if(num_blocks_selected
+                                       >= maximum_simultaneous_block_sends_now)
                        {
-                               JMutexAutoLock lock(m_blocks_sending_mutex);
-                               
-                               // Limit is dynamically lowered when building
-                               if(num_blocks_selected
-                                               >= maximum_simultaneous_block_sends_now)
-                               {
-                                       /*dstream<<"Not sending more blocks. Queue full. "
-                                                       <<m_blocks_sending.size()
-                                                       <<std::endl;*/
-                                       goto queue_full;
-                               }
-
-                               if(m_blocks_sending.find(p) != NULL)
-                                       continue;
+                               /*dstream<<"Not sending more blocks. Queue full. "
+                                               <<m_blocks_sending.size()
+                                               <<std::endl;*/
+                               goto queue_full;
                        }
-                       
+
+                       if(m_blocks_sending.find(p) != NULL)
+                               continue;
+               
                        /*
                                Do not go over-limit
                        */
@@ -519,7 +487,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
 #endif
 
                        /*
-                               Don't draw if not in sight
+                               Don't generate or send if not in sight
                        */
 
                        if(isBlockInSight(p, camera_pos, camera_dir, 10000*BS) == false)
@@ -531,8 +499,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                                Don't send already sent blocks
                        */
                        {
-                               JMutexAutoLock lock(m_blocks_sent_mutex);
-                               
                                if(m_blocks_sent.find(p) != NULL)
                                        continue;
                        }
@@ -546,12 +512,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                        bool block_is_invalid = false;
                        if(block != NULL)
                        {
-                               /*if(block->isIncomplete())
-                               {
-                                       has_incomplete_blocks = true;
-                                       continue;
-                               }*/
-
                                if(block->isDummy())
                                {
                                        surely_not_found_on_disk = true;
@@ -567,11 +527,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                                v2s16 chunkpos = map->sector_to_chunk(p2d);
                                if(map->chunkNonVolatile(chunkpos) == false)
                                        block_is_invalid = true;
-                               /*MapChunk *chunk = map->getChunk(chunkpos);
-                               if(chunk == NULL)
-                                       block_is_invalid = true;
-                               else if(chunk->getIsVolatile() == true)
-                                       block_is_invalid = true;*/
                        }
 
                        /*
@@ -598,11 +553,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                        */
                        if(block == NULL || surely_not_found_on_disk || block_is_invalid)
                        {
-                               //dstream<<"asd"<<std::endl;
-                               
-                               /*SharedPtr<JMutexAutoLock> lock
-                                               (m_num_blocks_in_emerge_queue.getLock());*/
-                               
                                //TODO: Get value from somewhere
                                // Allow only one block in emerge queue
                                if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
@@ -624,7 +574,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
                        }
 
                        /*
-                               Add block to queue
+                               Add block to send queue
                        */
 
                        PrioritySortedBlockTransfer q((float)d, p, peer_id);
@@ -638,7 +588,6 @@ queue_full:
 
        if(new_nearest_unsent_d != -1)
        {
-               JMutexAutoLock lock(m_blocks_sent_mutex);
                m_nearest_unsent_d = new_nearest_unsent_d;
        }
 }
@@ -743,7 +692,7 @@ void RemoteClient::SendObjectData(
        v3f playerpos = player->getPosition();
        v3f playerspeed = player->getSpeed();
 
-       v3s16 center_nodepos = floatToInt(playerpos);
+       v3s16 center_nodepos = floatToInt(playerpos, BS);
        v3s16 center = getNodeBlockPos(center_nodepos);
 
        s16 d_max = g_settings.getS16("active_object_range");
@@ -767,7 +716,6 @@ void RemoteClient::SendObjectData(
                                Ignore blocks that haven't been sent to the client
                        */
                        {
-                               JMutexAutoLock sentlock(m_blocks_sent_mutex);
                                if(m_blocks_sent.find(p) == NULL)
                                        continue;
                        }
@@ -861,8 +809,6 @@ skip_subsequent:
 
 void RemoteClient::GotBlock(v3s16 p)
 {
-       JMutexAutoLock lock(m_blocks_sending_mutex);
-       JMutexAutoLock lock2(m_blocks_sent_mutex);
        if(m_blocks_sending.find(p) != NULL)
                m_blocks_sending.remove(p);
        else
@@ -876,13 +822,6 @@ void RemoteClient::GotBlock(v3s16 p)
 
 void RemoteClient::SentBlock(v3s16 p)
 {
-       JMutexAutoLock lock(m_blocks_sending_mutex);
-       /*if(m_blocks_sending.size() > 15)
-       {
-               dstream<<"RemoteClient::SentBlock(): "
-                               <<"m_blocks_sending.size()="
-                               <<m_blocks_sending.size()<<std::endl;
-       }*/
        if(m_blocks_sending.find(p) == NULL)
                m_blocks_sending.insert(p, 0.0);
        else
@@ -892,9 +831,6 @@ void RemoteClient::SentBlock(v3s16 p)
 
 void RemoteClient::SetBlockNotSent(v3s16 p)
 {
-       JMutexAutoLock sendinglock(m_blocks_sending_mutex);
-       JMutexAutoLock sentlock(m_blocks_sent_mutex);
-
        m_nearest_unsent_d = 0;
        
        if(m_blocks_sending.find(p) != NULL)
@@ -905,9 +841,6 @@ void RemoteClient::SetBlockNotSent(v3s16 p)
 
 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
 {
-       JMutexAutoLock sendinglock(m_blocks_sending_mutex);
-       JMutexAutoLock sentlock(m_blocks_sent_mutex);
-
        m_nearest_unsent_d = 0;
        
        for(core::map<v3s16, MapBlock*>::Iterator
@@ -964,7 +897,7 @@ u32 PIChecksum(core::list<PlayerInfo> &l)
 Server::Server(
                std::string mapsavedir
        ):
-       m_env(new ServerMap(mapsavedir), dout_server),
+       m_env(new ServerMap(mapsavedir)),
        m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
        m_thread(this),
        m_emergethread(this),
@@ -1257,11 +1190,8 @@ void Server::AsyncRunStep()
        }
 
        /*
-               Update digging
-
-               NOTE: Some of this could be moved to RemoteClient
+               Check added and deleted active objects
        */
-#if 0
        {
                JMutexAutoLock envlock(m_env_mutex);
                JMutexAutoLock conlock(m_con_mutex);
@@ -1272,100 +1202,209 @@ void Server::AsyncRunStep()
                {
                        RemoteClient *client = i.getNode()->getValue();
                        Player *player = m_env.getPlayer(client->peer_id);
-
-                       JMutexAutoLock digmutex(client->m_dig_mutex);
-
-                       if(client->m_dig_tool_item == -1)
+                       v3s16 pos = floatToInt(player->getPosition(), BS);
+                       s16 radius = 32;
+
+                       core::map<u16, bool> removed_objects;
+                       core::map<u16, bool> added_objects;
+                       m_env.getRemovedActiveObjects(pos, radius,
+                                       client->m_known_objects, removed_objects);
+                       m_env.getAddedActiveObjects(pos, radius,
+                                       client->m_known_objects, added_objects);
+                       
+                       // Ignore if nothing happened
+                       if(removed_objects.size() == 0 && added_objects.size() == 0)
                                continue;
+                       
+                       std::string data_buffer;
+
+                       char buf[4];
+                       
+                       // Handle removed objects
+                       writeU16((u8*)buf, removed_objects.size());
+                       data_buffer.append(buf, 2);
+                       for(core::map<u16, bool>::Iterator
+                                       i = removed_objects.getIterator();
+                                       i.atEnd()==false; i++)
+                       {
+                               // Get object
+                               u16 id = i.getNode()->getKey();
+                               ServerActiveObject* obj = m_env.getActiveObject(id);
+
+                               // Add to data buffer for sending
+                               writeU16((u8*)buf, i.getNode()->getKey());
+                               data_buffer.append(buf, 2);
+                               
+                               // Remove from known objects
+                               client->m_known_objects.remove(i.getNode()->getKey());
 
-                       client->m_dig_time_remaining -= dtime;
+                               if(obj && obj->m_known_by_count > 0)
+                                       obj->m_known_by_count--;
+                       }
 
-                       if(client->m_dig_time_remaining > 0)
+                       // Handle added objects
+                       writeU16((u8*)buf, added_objects.size());
+                       data_buffer.append(buf, 2);
+                       for(core::map<u16, bool>::Iterator
+                                       i = added_objects.getIterator();
+                                       i.atEnd()==false; i++)
                        {
-                               client->m_time_from_building.set(0.0);
-                               continue;
+                               // Get object
+                               u16 id = i.getNode()->getKey();
+                               ServerActiveObject* obj = m_env.getActiveObject(id);
+                               
+                               // Get object type
+                               u8 type = ACTIVEOBJECT_TYPE_INVALID;
+                               if(obj == NULL)
+                                       dstream<<"WARNING: "<<__FUNCTION_NAME
+                                                       <<": NULL object"<<std::endl;
+                               else
+                                       type = obj->getType();
+
+                               // Add to data buffer for sending
+                               writeU16((u8*)buf, id);
+                               data_buffer.append(buf, 2);
+                               writeU8((u8*)buf, type);
+                               data_buffer.append(buf, 1);
+
+                               // Add to known objects
+                               client->m_known_objects.insert(i.getNode()->getKey(), false);
+
+                               if(obj)
+                                       obj->m_known_by_count++;
                        }
 
-                       v3s16 p_under = client->m_dig_position;
-                       
-                       // Mandatory parameter; actually used for nothing
-                       core::map<v3s16, MapBlock*> modified_blocks;
+                       // Send packet
+                       SharedBuffer<u8> reply(2 + data_buffer.size());
+                       writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
+                       memcpy((char*)&reply[2], data_buffer.c_str(),
+                                       data_buffer.size());
+                       // Send as reliable
+                       m_con.Send(client->peer_id, 0, reply, true);
 
-                       u8 material;
+                       dstream<<"INFO: Server: Sent object remove/add: "
+                                       <<removed_objects.size()<<" removed, "
+                                       <<added_objects.size()<<" added, "
+                                       <<"packet size is "<<reply.getSize()<<std::endl;
+               }
+       }
 
-                       try
+       /*
+               Send object messages
+       */
+       {
+               JMutexAutoLock envlock(m_env_mutex);
+               JMutexAutoLock conlock(m_con_mutex);
+
+               // Key = object id
+               // Value = data sent by object
+               core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
+
+               // Get active object messages from environment
+               for(;;)
+               {
+                       ActiveObjectMessage aom = m_env.getActiveObjectMessage();
+                       if(aom.id == 0)
+                               break;
+                       
+                       core::list<ActiveObjectMessage>* message_list = NULL;
+                       core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
+                       n = buffered_messages.find(aom.id);
+                       if(n == NULL)
                        {
-                               // Get material at position
-                               material = m_env.getMap().getNode(p_under).d;
-                               // If it's not diggable, do nothing
-                               if(content_diggable(material) == false)
-                               {
-                                       derr_server<<"Server: Not finishing digging: Node not diggable"
-                                                       <<std::endl;
-                                       client->m_dig_tool_item = -1;
-                                       break;
-                               }
+                               message_list = new core::list<ActiveObjectMessage>;
+                               buffered_messages.insert(aom.id, message_list);
                        }
-                       catch(InvalidPositionException &e)
+                       else
                        {
-                               derr_server<<"Server: Not finishing digging: Node not found"
-                                               <<std::endl;
-                               client->m_dig_tool_item = -1;
-                               break;
+                               message_list = n->getValue();
                        }
-                       
-                       // Create packet
-                       u32 replysize = 8;
-                       SharedBuffer<u8> reply(replysize);
-                       writeU16(&reply[0], TOCLIENT_REMOVENODE);
-                       writeS16(&reply[2], p_under.X);
-                       writeS16(&reply[4], p_under.Y);
-                       writeS16(&reply[6], p_under.Z);
-                       // Send as reliable
-                       m_con.SendToAll(0, reply, true);
-                       
-                       if(g_settings.getBool("creative_mode") == false)
-                       {
-                               // Add to inventory and send inventory
-                               InventoryItem *item = new MaterialItem(material, 1);
-                               player->inventory.addItem("main", item);
-                               SendInventory(player->peer_id);
+                       message_list->push_back(aom);
+               }
+               
+               // Route data to every client
+               for(core::map<u16, RemoteClient*>::Iterator
+                       i = m_clients.getIterator();
+                       i.atEnd()==false; i++)
+               {
+                       RemoteClient *client = i.getNode()->getValue();
+                       std::string reliable_data;
+                       std::string unreliable_data;
+                       // Go through all objects in message buffer
+                       for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
+                                       j = buffered_messages.getIterator();
+                                       j.atEnd()==false; j++)
+                       {
+                               // If object is not known by client, skip it
+                               u16 id = j.getNode()->getKey();
+                               if(client->m_known_objects.find(id) == NULL)
+                                       continue;
+                               // Get message list of object
+                               core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
+                               // Go through every message
+                               for(core::list<ActiveObjectMessage>::Iterator
+                                               k = list->begin(); k != list->end(); k++)
+                               {
+                                       // Compose the full new data with header
+                                       ActiveObjectMessage aom = *k;
+                                       std::string new_data;
+                                       // Add header (object id + length)
+                                       char header[4];
+                                       writeU16((u8*)&header[0], aom.id);
+                                       writeU16((u8*)&header[2], aom.datastring.size());
+                                       new_data.append(header, 4);
+                                       // Add data
+                                       new_data += aom.datastring;
+                                       // Add data to buffer
+                                       if(aom.reliable)
+                                               reliable_data += new_data;
+                                       else
+                                               unreliable_data += new_data;
+                               }
                        }
-
                        /*
-                               Remove the node
-                               (this takes some time so it is done after the quick stuff)
+                               reliable_data and unreliable_data are now ready.
+                               Send them.
                        */
-                       m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
-                       
-                       /*
-                               Update water
-                       */
-                       
-                       // Update water pressure around modification
-                       // This also adds it to m_flow_active_nodes if appropriate
-
-                       MapVoxelManipulator v(&m_env.getMap());
-                       v.m_disable_water_climb =
-                                       g_settings.getBool("disable_water_climb");
-                       
-                       VoxelArea area(p_under-v3s16(1,1,1), p_under+v3s16(1,1,1));
-
-                       try
+                       if(reliable_data.size() > 0)
                        {
-                               v.updateAreaWaterPressure(area, m_flow_active_nodes);
+                               SharedBuffer<u8> reply(2 + reliable_data.size());
+                               writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
+                               memcpy((char*)&reply[2], reliable_data.c_str(),
+                                               reliable_data.size());
+                               // Send as reliable
+                               m_con.Send(client->peer_id, 0, reply, true);
                        }
-                       catch(ProcessingLimitException &e)
+                       if(unreliable_data.size() > 0)
                        {
-                               dstream<<"Processing limit reached (1)"<<std::endl;
+                               SharedBuffer<u8> reply(2 + unreliable_data.size());
+                               writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
+                               memcpy((char*)&reply[2], unreliable_data.c_str(),
+                                               unreliable_data.size());
+                               // Send as unreliable
+                               m_con.Send(client->peer_id, 0, reply, false);
                        }
-                       
-                       v.blitBack(modified_blocks);
+                       if(reliable_data.size() > 0 || unreliable_data.size() > 0)
+                       {
+                               dstream<<"INFO: Server: Size of object message data: "
+                                               <<"reliable: "<<reliable_data.size()
+                                               <<", unreliable: "<<unreliable_data.size()
+                                               <<std::endl;
+                       }
+               }
+
+               // Clear buffered_messages
+               for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
+                               i = buffered_messages.getIterator();
+                               i.atEnd()==false; i++)
+               {
+                       delete i.getNode()->getValue();
                }
        }
-#endif
 
-       // Send object positions
+       /*
+               Send object positions
+       */
        {
                float &counter = m_objectdata_timer;
                counter += dtime;
@@ -1485,7 +1524,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                return;
        }
        
-       //u8 peer_ser_ver = peer->serialization_version;
        u8 peer_ser_ver = getClient(peer->id)->serialization_version;
 
        try
@@ -1595,7 +1633,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                SharedBuffer<u8> reply(2+1+6);
                writeU16(&reply[0], TOCLIENT_INIT);
                writeU8(&reply[2], deployed);
-               writeV3S16(&reply[3], floatToInt(player->getPosition()+v3f(0,BS/2,0)));
+               writeV3S16(&reply[3], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
                // Send as reliable
                m_con.Send(peer_id, 0, reply, true);
 
@@ -1892,6 +1930,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                {
                                        derr_server<<"Server: Not finishing digging: Node not diggable"
                                                        <<std::endl;
+
+                                       // Client probably has wrong data.
+                                       // Set block not sent, so that client will get
+                                       // a valid one.
+                                       dstream<<"Client "<<peer_id<<" tried to dig "
+                                                       <<"node from invalid position; setting"
+                                                       <<" MapBlock not sent."<<std::endl;
+                                       RemoteClient *client = getClient(peer_id);
+                                       v3s16 blockpos = getNodeBlockPos(p_under);
+                                       client->SetBlockNotSent(blockpos);
+                                               
                                        return;
                                }
                                // Get mineral
@@ -2088,7 +2137,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                }
 
                                // Reset build time counter
-                               getClient(peer->id)->m_time_from_building.set(0.0);
+                               getClient(peer->id)->m_time_from_building = 0.0;
                                
                                // Create node data
                                MaterialItem *mitem = (MaterialItem*)item;
@@ -2166,9 +2215,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                }
 
                                v3s16 block_pos_i_on_map = block->getPosRelative();
-                               v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map);
+                               v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
 
-                               v3f pos = intToFloat(p_over);
+                               v3f pos = intToFloat(p_over, BS);
                                pos -= block_pos_f_on_map;
                                
                                /*dout_server<<"pos="
@@ -3060,6 +3109,7 @@ void Server::SendBlocks(float dtime)
        DSTACK(__FUNCTION_NAME);
 
        JMutexAutoLock envlock(m_env_mutex);
+       JMutexAutoLock conlock(m_con_mutex);
 
        //TimeTaker timer("Server::SendBlocks");
 
@@ -3087,8 +3137,6 @@ void Server::SendBlocks(float dtime)
        // Lowest is most important.
        queue.sort();
 
-       JMutexAutoLock conlock(m_con_mutex);
-
        for(u32 i=0; i<queue.size(); i++)
        {
                //TODO: Calculate limit dynamically
@@ -3268,7 +3316,7 @@ Player *Server::emergePlayer(const char *name, const char *password,
                                0,
                                45, //64,
                                0
-               )));
+               ), BS));
 #endif
 #if 0
                f32 groundheight = 0;
index 9582c99dd0ffd96e93523359827e23b001af5b20..292e2d5cd84affc902812010e3fb272b079c903e 100644 (file)
@@ -239,13 +239,6 @@ public:
                pending_serialization_version = SER_FMT_VER_INVALID;
                m_nearest_unsent_d = 0;
                m_nearest_unsent_reset_timer = 0.0;
-
-               m_blocks_sent_mutex.Init();
-               m_blocks_sending_mutex.Init();
-               
-               /*m_dig_mutex.Init();
-               m_dig_time_remaining = 0;
-               m_dig_tool_item = -1;*/
        }
        ~RemoteClient()
        {
@@ -279,7 +272,6 @@ public:
 
        s32 SendingCount()
        {
-               JMutexAutoLock lock(m_blocks_sending_mutex);
                return m_blocks_sending.size();
        }
        
@@ -290,8 +282,6 @@ public:
 
        void PrintInfo(std::ostream &o)
        {
-               JMutexAutoLock l2(m_blocks_sent_mutex);
-               JMutexAutoLock l3(m_blocks_sending_mutex);
                o<<"RemoteClient "<<peer_id<<": "
                                <<", m_blocks_sent.size()="<<m_blocks_sent.size()
                                <<", m_blocks_sending.size()="<<m_blocks_sending.size()
@@ -302,30 +292,21 @@ public:
        }
 
        // Time from last placing or removing blocks
-       MutexedVariable<float> m_time_from_building;
+       float m_time_from_building;
        
        /*JMutex m_dig_mutex;
        float m_dig_time_remaining;
        // -1 = not digging
        s16 m_dig_tool_item;
        v3s16 m_dig_position;*/
-
-private:
+       
        /*
-               All members that are accessed by many threads should
-               obviously be behind a mutex. The threads include:
-               - main thread (calls step())
-               - server thread (calls AsyncRunStep() and Receive())
-               - emerge thread 
+               List of active objects that the client knows of.
+               Value is dummy.
        */
-       
-       //TODO: core::map<v3s16, MapBlock*> m_active_blocks
-       //NOTE: Not here, it should be server-wide!
-
-       // Number of blocks in the emerge queue that have this client as
-       // a receiver. Used for throttling network usage.
-       //MutexedVariable<s16> m_num_blocks_in_emerge_queue;
+       core::map<u16, bool> m_known_objects;
 
+private:
        /*
                Blocks that have been sent to client.
                - These don't have to be sent again.
@@ -339,7 +320,7 @@ private:
        s16 m_nearest_unsent_d;
        v3s16 m_last_center;
        float m_nearest_unsent_reset_timer;
-       JMutex m_blocks_sent_mutex;
+       
        /*
                Blocks that are currently on the line.
                This is used for throttling the sending of blocks.
@@ -349,7 +330,6 @@ private:
                Value is time from sending. (not used at the moment)
        */
        core::map<v3s16, float> m_blocks_sending;
-       JMutex m_blocks_sending_mutex;
 
        /*
                Count of excess GotBlocks().
@@ -361,15 +341,6 @@ private:
        u32 m_excess_gotblocks;
 };
 
-/*struct ServerSettings
-{
-       ServerSettings()
-       {
-               creative_mode = false;
-       }
-       bool creative_mode;
-};*/
-
 class Server : public con::PeerHandler
 {
 public:
@@ -470,7 +441,7 @@ private:
        // NOTE: If connection and environment are both to be locked,
        // environment shall be locked first.
        JMutex m_env_mutex;
-       Environment m_env;
+       ServerEnvironment m_env;
 
        JMutex m_con_mutex;
        con::Connection m_con;
diff --git a/src/serverobject.cpp b/src/serverobject.cpp
new file mode 100644 (file)
index 0000000..ffb6059
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "serverobject.h"
+
+ServerActiveObject::ServerActiveObject(u16 id, v3f pos):
+       ActiveObject(id),
+       m_known_by_count(0),
+       m_removed(false),
+       m_base_position(pos)
+{
+}
+
+ServerActiveObject::~ServerActiveObject()
+{
+}
+
+TestSAO::TestSAO(u16 id, v3f pos):
+       ServerActiveObject(id, pos),
+       m_timer1(0),
+       m_age(0)
+{
+}
+
+void TestSAO::step(float dtime, Queue<ActiveObjectMessage> &messages)
+{
+       m_age += dtime;
+       if(m_age > 10)
+       {
+               m_removed = true;
+               return;
+       }
+
+       m_base_position.Y += dtime * BS * 2;
+       if(m_base_position.Y > 8*BS)
+               m_base_position.Y = 2*BS;
+
+       m_timer1 -= dtime;
+       if(m_timer1 < 0.0)
+       {
+               m_timer1 += 0.125;
+               //dstream<<"TestSAO: id="<<getId()<<" sending data"<<std::endl;
+
+               std::string data;
+
+               data += itos(0); // 0 = position
+               data += " ";
+               data += itos(m_base_position.X);
+               data += " ";
+               data += itos(m_base_position.Y);
+               data += " ";
+               data += itos(m_base_position.Z);
+
+               //ActiveObjectMessage aom(getId(), true, data);
+               ActiveObjectMessage aom(getId(), false, data);
+               messages.push_back(aom);
+       }
+}
+
diff --git a/src/serverobject.h b/src/serverobject.h
new file mode 100644 (file)
index 0000000..d0866b4
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef SERVEROBJECT_HEADER
+#define SERVEROBJECT_HEADER
+
+#include "common_irrlicht.h"
+#include "activeobject.h"
+#include "utility.h"
+
+/*
+
+Some planning
+-------------
+
+* Server environment adds an active object, which gets the id 1
+* The active object list is scanned for each client once in a while,
+  and it finds out what objects have been added that are not known
+  by the client yet. This scan is initiated by the server and the
+  result ends up directly to the server.
+* A network packet is created with the info and sent to the client.
+
+*/
+
+class ServerActiveObject : public ActiveObject
+{
+public:
+       ServerActiveObject(u16 id, v3f pos=v3f(0,0,0));
+       virtual ~ServerActiveObject();
+
+       v3f getBasePosition()
+       {
+               return m_base_position;
+       }
+       
+       /*
+               Step object in time.
+               Messages added to messages are sent to client over network.
+       */
+       virtual void step(float dtime, Queue<ActiveObjectMessage> &messages){}
+       
+       // Number of players which know about this one
+       u16 m_known_by_count;
+       /*
+               Whether this object is to be removed when nobody knows about
+               it anymore.
+               Removal is delayed to preserve the id for the time during which
+               it could be confused to some other object by some client.
+       */
+       bool m_removed;
+       
+protected:
+       v3f m_base_position;
+};
+
+class TestSAO : public ServerActiveObject
+{
+public:
+       TestSAO(u16 id, v3f pos);
+       u8 getType() const
+       {
+               return ACTIVEOBJECT_TYPE_TEST;
+       }
+       void step(float dtime, Queue<ActiveObjectMessage> &messages);
+private:
+       float m_timer1;
+       float m_age;
+};
+
+#endif
+
index 8c81aba9170c8c8f1f3a5b7e72646dc5760dc50d..8db2c276065b50848d32081eb9aaf7a214ad685b 100644 (file)
@@ -1738,5 +1738,30 @@ inline std::string wrap_rows(const std::string &from, u32 rowlen)
 #define MYMIN(a,b) ((a)<(b)?(a):(b))
 #define MYMAX(a,b) ((a)>(b)?(a):(b))
 
+/*
+       Returns integer position of node in given floating point position
+*/
+inline v3s16 floatToInt(v3f p, f32 d)
+{
+       v3s16 p2(
+               (p.X + (p.X>0 ? BS/2 : -BS/2))/d,
+               (p.Y + (p.Y>0 ? BS/2 : -BS/2))/d,
+               (p.Z + (p.Z>0 ? BS/2 : -BS/2))/d);
+       return p2;
+}
+
+/*
+       Returns floating point position of node in given integer position
+*/
+inline v3f intToFloat(v3s16 p, f32 d)
+{
+       v3f p2(
+               (f32)p.X * d,
+               (f32)p.Y * d,
+               (f32)p.Z * d
+       );
+       return p2;
+}
+
 #endif