diff options
author | Perttu Ahola <celeron55@gmail.com> | 2011-02-21 00:45:14 +0200 |
---|---|---|
committer | Perttu Ahola <celeron55@gmail.com> | 2011-02-21 00:45:14 +0200 |
commit | c57637b4c39319e0c0d5d80d0ae2884aec66d691 (patch) | |
tree | 72ba35937c701ec32d07bba3b6dde6fb2a9f2bc0 | |
parent | f5ff378dd02431cdcf658b210509b170ea2135d1 (diff) | |
download | minetest-c57637b4c39319e0c0d5d80d0ae2884aec66d691.tar.gz minetest-c57637b4c39319e0c0d5d80d0ae2884aec66d691.tar.bz2 minetest-c57637b4c39319e0c0d5d80d0ae2884aec66d691.zip |
Temporary commit; lots of test code and stuff
-rw-r--r-- | data/grass.png | bin | 1675 -> 966 bytes | |||
-rw-r--r-- | data/stone.png | bin | 1563 -> 846 bytes | |||
-rw-r--r-- | src/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/activeobject.h | 71 | ||||
-rw-r--r-- | src/client.cpp | 158 | ||||
-rw-r--r-- | src/client.h | 33 | ||||
-rw-r--r-- | src/clientobject.cpp | 169 | ||||
-rw-r--r-- | src/clientobject.h | 88 | ||||
-rw-r--r-- | src/clientserver.h | 25 | ||||
-rw-r--r-- | src/environment.cpp | 843 | ||||
-rw-r--r-- | src/environment.h | 177 | ||||
-rw-r--r-- | src/jthread/jmutex.h | 2 | ||||
-rw-r--r-- | src/main.cpp | 91 | ||||
-rw-r--r-- | src/map.cpp | 177 | ||||
-rw-r--r-- | src/map.h | 30 | ||||
-rw-r--r-- | src/mapblock.cpp | 12 | ||||
-rw-r--r-- | src/mapblockobject.cpp | 20 | ||||
-rw-r--r-- | src/mapnode.h | 26 | ||||
-rw-r--r-- | src/player.cpp | 18 | ||||
-rw-r--r-- | src/player.h | 10 | ||||
-rw-r--r-- | src/server.cpp | 454 | ||||
-rw-r--r-- | src/server.h | 45 | ||||
-rw-r--r-- | src/serverobject.cpp | 75 | ||||
-rw-r--r-- | src/serverobject.h | 87 | ||||
-rw-r--r-- | src/utility.h | 25 |
25 files changed, 1897 insertions, 743 deletions
diff --git a/data/grass.png b/data/grass.png Binary files differindex 8fe9078ca..b5c1559f6 100644 --- a/data/grass.png +++ b/data/grass.png diff --git a/data/stone.png b/data/stone.png Binary files differindex c7a453e3f..d085cb8dd 100644 --- a/data/stone.png +++ b/data/stone.png diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c0301cc80..b26294113 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 index 000000000..103d90d12 --- /dev/null +++ b/src/activeobject.h @@ -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 + diff --git a/src/client.cpp b/src/client.cpp index 21c911ec6..4ad1f1226 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -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; diff --git a/src/client.h b/src/client.h index 00fd3a5ed..fb1e70722 100644 --- a/src/client.h +++ b/src/client.h @@ -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 index 000000000..46db389cd --- /dev/null +++ b/src/clientobject.cpp @@ -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 index 000000000..454531aec --- /dev/null +++ b/src/clientobject.h @@ -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 + diff --git a/src/clientserver.h b/src/clientserver.h index 07b1cf60f..66ee58473 100644 --- a/src/clientserver.h +++ b/src/clientserver.h @@ -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 diff --git a/src/environment.cpp b/src/environment.cpp index 07437ec40..5e16602e0 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -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> ¤t_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> ¤t_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 + + diff --git a/src/environment.h b/src/environment.h index dfc60673b..1a786af23 100644 --- a/src/environment.h +++ b/src/environment.h @@ -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> ¤t_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> ¤t_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 + diff --git a/src/jthread/jmutex.h b/src/jthread/jmutex.h index 39bd95f02..9ce013096 100644 --- a/src/jthread/jmutex.h +++ b/src/jthread/jmutex.h @@ -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> diff --git a/src/main.cpp b/src/main.cpp index 2754c324b..f0bc6d7a2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -160,32 +160,23 @@ TODO: Make fetching sector's blocks more efficient when rendering TODO: Flowing water animation
-NOTE(FIXED): A lock condition is possible:
- 1) MapBlock::updateMesh() is called from client asynchronously:
- - AsyncProcessData() -> Map::updateMeshes()
- 2) Asynchronous locks m_temp_mods_mutex
- 3) MapBlock::updateMesh() is called from client synchronously:
- - Client::step() -> Environment::step()
- 4) Synchronous starts waiting for m_temp_mods_mutex
- 5) Asynchronous calls getTexture, which starts waiting for main thread
-
Configuration:
--------------
-TODO: Make the video backend selectable
-
Client:
-------
TODO: Untie client network operations from framerate
- Needs some input queues or something
-TODO: Make morning and evening transition more smooth and maybe shorter
+SUGG: Make morning and evening transition more smooth and maybe shorter
-TODO: Don't update all meshes always on single node changes, but
+SUGG: Don't update all meshes always on single node changes, but
check which ones should be updated
- implement Map::updateNodeMeshes()
+TODO: Remove IrrlichtWrapper
+
Server:
-------
@@ -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
the starting position
-TODO: Save players with inventories to disk
-TODO: Players to be saved as text in map/players/<name>
-
TODO: Copy the text of the last picked sign to inventory in creative
mode
TODO: Check what goes wrong with caching map to disk (Kray)
- Nothing?
-TODO: When server sees that client is removing an inexistent block to
+TODO: When server sees that client is removing an inexistent block in
an existent position, resend the MapBlock.
FIXME: Server went into some infinite PeerNotFoundException loop
@@ -237,6 +225,11 @@ Block object server side: - TODO: For incoming blocks, time difference is calculated and
objects are stepped according to it.
+- When an active object goes far from a player, either delete
+ it or store it statically.
+- When a statically stored active object comes near a player,
+ recreate the active object
+
Map:
----
@@ -345,18 +338,18 @@ Doing now (most important at the top): #include <fstream>
#include <jmutexautolock.h>
#include <locale.h>
+#include "main.h"
#include "common_irrlicht.h"
#include "debug.h"
#include "map.h"
#include "player.h"
-#include "main.h"
#include "test.h"
-#include "environment.h"
+//#include "environment.h"
#include "server.h"
#include "client.h"
-#include "serialization.h"
+//#include "serialization.h"
#include "constants.h"
-#include "strfnd.h"
+//#include "strfnd.h"
#include "porting.h"
#include "irrlichtwrapper.h"
#include "gettime.h"
@@ -905,8 +898,12 @@ class RandomInputHandler : public InputHandler public:
RandomInputHandler()
{
+ leftdown = false;
+ rightdown = false;
leftclicked = false;
rightclicked = false;
+ leftreleased = false;
+ rightreleased = false;
for(u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
keydown[i] = false;
}
@@ -925,11 +922,11 @@ public: virtual bool getLeftState()
{
- return false;
+ return leftdown;
}
virtual bool getRightState()
{
- return false;
+ return rightdown;
}
virtual bool getLeftClicked()
@@ -951,17 +948,19 @@ public: virtual bool getLeftReleased()
{
- return false;
+ return leftreleased;
}
virtual bool getRightReleased()
{
- return false;
+ return rightreleased;
}
virtual void resetLeftReleased()
{
+ leftreleased = false;
}
virtual void resetRightReleased()
{
+ rightreleased = false;
}
virtual void step(float dtime)
@@ -971,22 +970,6 @@ public: counter1 -= dtime;
if(counter1 < 0.0)
{
- counter1 = 0.1*Rand(1,10);
- /*if(g_selected_material < USEFUL_CONTENT_COUNT-1)
- g_selected_material++;
- else
- g_selected_material = 0;*/
- if(g_selected_item < PLAYER_INVENTORY_SIZE-1)
- g_selected_item++;
- else
- g_selected_item = 0;
- }
- }
- {
- static float counter1 = 0;
- counter1 -= dtime;
- if(counter1 < 0.0)
- {
counter1 = 0.1*Rand(1, 40);
keydown[irr::KEY_SPACE] = !keydown[irr::KEY_SPACE];
}
@@ -1033,7 +1016,11 @@ public: if(counter1 < 0.0)
{
counter1 = 0.1*Rand(1, 30);
- leftclicked = true;
+ leftdown = !leftdown;
+ if(leftdown)
+ leftclicked = true;
+ if(!leftdown)
+ leftreleased = true;
}
}
{
@@ -1041,8 +1028,12 @@ public: counter1 -= dtime;
if(counter1 < 0.0)
{
- counter1 = 0.1*Rand(1, 20);
- rightclicked = true;
+ counter1 = 0.1*Rand(1, 15);
+ rightdown = !rightdown;
+ if(rightdown)
+ rightclicked = true;
+ if(!rightdown)
+ rightreleased = true;
}
}
mousepos += mousespeed;
@@ -1056,8 +1047,12 @@ private: bool keydown[KEY_KEY_CODES_COUNT];
v2s32 mousepos;
v2s32 mousespeed;
+ bool leftdown;
+ bool rightdown;
bool leftclicked;
bool rightclicked;
+ bool leftreleased;
+ bool rightreleased;
};
void updateViewingRange(f32 frametime_in, Client *client)
@@ -2486,11 +2481,9 @@ int main(int argc, char *argv[]) camera->setTarget(camera_position + camera_direction * 100.0);
if(FIELD_OF_VIEW_TEST){
- //client.m_env.getMap().updateCamera(v3f(0,0,0), v3f(0,0,1));
client.updateCamera(v3f(0,0,0), v3f(0,0,1));
}
else{
- //client.m_env.getMap().updateCamera(camera_position, camera_direction);
//TimeTaker timer("client.updateCamera");
client.updateCamera(camera_position, camera_direction);
}
@@ -2585,7 +2578,7 @@ int main(int argc, char *argv[]) core::aabbox3d<f32> nodehilightbox;
f32 mindistance = BS * 1001;
- v3s16 pos_i = floatToInt(player_position);
+ v3s16 pos_i = floatToInt(player_position, BS);
/*std::cout<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
<<std::endl;*/
@@ -2615,7 +2608,7 @@ int main(int argc, char *argv[]) }
v3s16 np(x,y,z);
- v3f npf = intToFloat(np);
+ v3f npf = intToFloat(np, BS);
f32 d = 0.01;
@@ -2723,7 +2716,7 @@ int main(int argc, char *argv[]) const float d = 0.502;
core::aabbox3d<f32> nodebox
(-BS*d, -BS*d, -BS*d, BS*d, BS*d, BS*d);
- v3f nodepos_f = intToFloat(nodepos);
+ v3f nodepos_f = intToFloat(nodepos, BS);
nodebox.MinEdge += nodepos_f;
nodebox.MaxEdge += nodepos_f;
nodehilightbox = nodebox;
diff --git a/src/map.cpp b/src/map.cpp index 159682696..c92039664 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -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: "; @@ -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); diff --git a/src/mapblock.cpp b/src/mapblock.cpp index a1e3c6694..d489ec8ac 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -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); } } diff --git a/src/mapblockobject.cpp b/src/mapblockobject.cpp index ab12afc8e..ff58fd045 100644 --- a/src/mapblockobject.cpp +++ b/src/mapblockobject.cpp @@ -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; diff --git a/src/mapnode.h b/src/mapnode.h index d67b9629e..7819d701d 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -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 diff --git a/src/player.cpp b/src/player.cpp index 9f8a97e7f..07879c21a 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -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( diff --git a/src/player.h b/src/player.h index 16de6c924..710a9e0ed 100644 --- a/src/player.h +++ b/src/player.h @@ -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: diff --git a/src/server.cpp b/src/server.cpp index 26d0d5d75..6f04ef33a 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -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; diff --git a/src/server.h b/src/server.h index 9582c99dd..292e2d5cd 100644 --- a/src/server.h +++ b/src/server.h @@ -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 index 000000000..ffb6059dc --- /dev/null +++ b/src/serverobject.cpp @@ -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 index 000000000..d0866b4c3 --- /dev/null +++ b/src/serverobject.h @@ -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 + diff --git a/src/utility.h b/src/utility.h index 8c81aba91..8db2c2760 100644 --- a/src/utility.h +++ b/src/utility.h @@ -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 |