From c57637b4c39319e0c0d5d80d0ae2884aec66d691 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Mon, 21 Feb 2011 00:45:14 +0200 Subject: [PATCH] Temporary commit; lots of test code and stuff --- data/grass.png | Bin 1675 -> 966 bytes data/stone.png | Bin 1563 -> 846 bytes src/CMakeLists.txt | 4 + src/activeobject.h | 71 ++++ src/client.cpp | 158 +++++--- src/client.h | 33 +- src/clientobject.cpp | 169 +++++++++ src/clientobject.h | 88 +++++ src/clientserver.h | 25 ++ src/environment.cpp | 843 +++++++++++++++++++++++++++++++---------- src/environment.h | 185 +++++++-- src/jthread/jmutex.h | 2 +- src/main.cpp | 91 ++--- src/map.cpp | 177 +++++---- src/map.h | 30 +- src/mapblock.cpp | 12 +- src/mapblockobject.cpp | 20 +- src/mapnode.h | 26 -- src/player.cpp | 18 +- src/player.h | 10 +- src/server.cpp | 484 ++++++++++++----------- src/server.h | 47 +-- src/serverobject.cpp | 75 ++++ src/serverobject.h | 87 +++++ src/utility.h | 25 ++ 25 files changed, 1917 insertions(+), 763 deletions(-) create mode 100644 src/activeobject.h create mode 100644 src/clientobject.cpp create mode 100644 src/clientobject.h create mode 100644 src/serverobject.cpp create mode 100644 src/serverobject.h diff --git a/data/grass.png b/data/grass.png index 8fe9078caffee8e3a78b9ccd6b70b1782ad8955d..b5c1559f6b9fedf23e48b48eef03524a38bda130 100644 GIT binary patch delta 81 zcmeC?J;pvk*_DB@ILO_JVcj{ImkbOHY)RhkE)4%caKYZ?lYt_f1s;*b3=G`DAk4@x eYmNj^kiEpy*OmP?lQ18vct!QbtDAM1M+LhR$BJGp{41c zk=*Q$BtxD0J}#DX+XOt19&$;c3!O$$FeAbXtc+QXhLYV<|2kL zTFoJ{A&o&_FG%iiu-_6Xy+YTa7w(EV&@13<-;5L4n+S3vbV+DK+5?jX>;}osJtzI+ ziDFt1SFk3GVQnRxAl?cw*~*XXTiSZFz*pW{xX9%n%x&-scC{?|%0HP`x908fZ81lq zM-F9B4OZvQ?pmeu&+wvixl4gORKRV6s(D-R@lG^m1aJ3H+)8g>1nRa$tFodpYs06U al8f56>nY{ail`-B$DhY{?|=PxdiV>7Fn_ZE diff --git a/data/stone.png b/data/stone.png index c7a453e3f7be95a2dd091542441108ad05b1bca5..d085cb8dd267ade7ae0d8a1e9ac78e0f757acb62 100644 GIT binary patch delta 824 zcmV-81IPTE49*6SBYyw^b5ch_0Itp)=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L z01FcU01FcV0GgZ_00007bV*G`2ipP@3L_XS6NkJ200PcQL_t(2&jrC-Z_`!)0ASzk z<8$Ks9Op*bWa%vhu})(*2?Ukkc^W?n-g#kvX3~%*q)9+K7Jn^L(>4hSZ5q2tNMifM zck_MZt3O`%2bZRz6*N^81VI2-*OU2jnUT3BAVwfI0iHYSFvMQ6F_1#n8@2ZC{dF87 z7L1+g-~YVL$rK7aOHlpM`P}n9IXCwkJH!5^WtcoC&_@q`$nzMGL>RfgyW)6yzjf$u zVoTFhMfUyJRDV^H&rFzy9=yAvT&M&zzgy@KdwV+$8Dv zc21GmR;7ON*{M}Z^#0+YEXhW(*xcG?Sjx~09zaOB? zeEISPj(_ksP`I_{ zdD-m{>lOXr=(~}9O%ln;`}YmAbg;iSwa2~wDDeF|rt$gOxp(*8Y-V#D^YrPn{&+$^ z|NS=&siGv+D)p40R7D~g9s;pwn(sb*Fe}wwx09qKg79o`QL$?D?%qMC`=3@&@3s#o z(=qAE$A4u-^VUlr2V2cn5aONv0|-GDrAR_ZQojOdpkSJ6vlzMn0000)qcFYTyInZpB86jjK z%<`SDZgc(aXQ0lE%xE`449PtIU_a%`t}VMRsXVD)h$w{MoHND%fKrNt2tqg^j1VA% zs;pj5h(rj&IbnXNKg>L31@@>0jhrLmDU?x3W1yp#y9|@RC11t2>`Ba#t=X# z0|3>js7e$lxZsR4U_gNiDL8T_7;vDBa>*Go5I{L)k^!m+3KD2nKH^7cAVhaS#`yBR!QK$xnt=QIH6*&jucASZ$m z6)uTD!UbVmjjfP`qoP0*P}i#d+`xzsgBtMl4tA_IKD%%(#uE~Yvg6$pZOT3Crm)Ss za$5J*oj?4v&$>+yr|JG~pUU>G%5{sWbB##}oe(}|$Y%wqZmE_-e`uK`+TY|i$d2>R zo&*oOzt8@d>sLXo%@y}Io~XLwUzp~R-m%5qy~^?VZ`q}5?H$urx7-Q(Vn>?MB)7uT zov&tYE6lKuGqT!aTW!-^|MRqezWZ{}+_r0@;7Z={s}(O&&pvlKy5tfa7n}Th^Q$<& zPztfPeTO;h(PWJeuX`~AbkVa=JJmXUv9sBd1$TFORIFOrwsFPV)|WORs)-##6-sVReC*W9@p2i zcz(mJ$C*Z14&$~*ZfU-CCvEwK0p6ZruAL9t6O!L(imolo4~p1sG(;D;@apc}S?^-) zD}N1WjLE(1Uv{W=#Dm)#jwfy^b6K&V&|>r0Kb@K`L?plROgmq?x1}*L@7dk-i8en@ zTNCg0HpEN2Co;OGq%6Rx#H!8g%HiRe7Qw}*ZmqQF=N~eg8X6ziSXvgeOk-)1Yw!HP z#Czzye-9PRe)x-fLt@NE($@JXj`NURR zm-HxgOIXbW_cIgEh1D;Lo8c0bH@)L)%ZsLlb}PbbiX)Rs@bMbk0VeQM&G3r}IsM;^ zuxl(V2{?GqId_6V-a*-!5;o@M>dCrern#kqUbauk)qb0tC~$q}YiwL^piMk6*1{pDxpvj%Px>4!-|t~MQWRxNubZ_i+xEZH9QCnFof$QD z@+O<2nAaMaa&FGxgbll|Kf=K+#({BFQ)>IyS%rHyt+Q?QC@%=CG_}^vk%n&HM`q__ R8XnM(I`{?nmiR2)`X7dG@?`)3 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 + +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 + +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; igetPos(), 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 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 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 +#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 m_fetchblock_history; - JMutex m_fetchblock_mutex;*/ - core::list 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 + +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"<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="<>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 + +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::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::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 "<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::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::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 "<timerUpdate()", g_device); + m_map->timerUpdate(dtime); + } + + /* + Handle players + */ + for(core::list::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::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 objects_to_remove; + for(core::map::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="<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::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::Node *n; + n = m_active_objects.find(id); + if(n == NULL) + return NULL; + return n->getValue(); +} + +bool isFreeServerActiveObjectId(u16 id, + core::map &objects) +{ + if(id == 0) + return false; + + for(core::map::Iterator + i = objects.getIterator(); + i.atEnd()==false; i++) + { + if(i.getNode()->getKey() == id) + return false; + } + return true; +} + +u16 getFreeServerActiveObjectId( + core::map &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"<setId(new_id); + } + if(isFreeServerActiveObjectId(object->getId(), m_active_objects) == false) + { + dstream<<"WARNING: ServerEnvironment::addActiveObject(): " + <<"id is not free ("<getId()<<")"<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 ¤t_objects, + core::map &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::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::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 ¤t_objects, + core::map &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::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"<m_removed == false) + { + f32 distance_f = object->getBasePosition().getDistanceFrom(pos_f); + /*dstream<<"removed == false" + <<"distance_f = "<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 "<::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::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::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 &objects) { - return m_daynight_ratio; + if(id == 0) + return false; + + for(core::map::Iterator + i = objects.getIterator(); + i.atEnd()==false; i++) + { + if(i.getNode()->getKey() == id) + return false; + } + return true; } +u16 getFreeClientActiveObjectId( + core::map &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"<setId(new_id); + } + if(isFreeClientActiveObjectId(object->getId(), m_active_objects) == false) + { + dstream<<"WARNING: ClientEnvironment::addActiveObject(): " + <<"id is not free ("<getId()<<")"<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="<setId(id); + + addActiveObject(obj); +} + +void ClientEnvironment::removeActiveObject(u16 id) +{ + dstream<<"ClientEnvironment::removeActiveObject(): " + <<"id="<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="<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 @@ -39,51 +40,175 @@ class Environment { public: // Environment will delete the map passed to the constructor - Environment(Map *map, std::ostream &dout); - ~Environment(); - /* - This can do anything to the environment, such as removing - timed-out players. - Also updates Map's timers. - */ - void step(f32 dtime); - - Map & getMap(); + Environment(); + virtual ~Environment(); /* - Environment deallocates players after use. + Step everything in environment. + - Move players + - Step mobs + - Run timers of map */ - void addPlayer(Player *player); + virtual void step(f32 dtime) = 0; + + virtual Map & getMap() = 0; + + 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 getPlayers(); core::list getPlayers(bool ignore_disconnected); void printPlayers(std::ostream &o); - void serializePlayers(const std::string &savedir); - // This loads players as ServerRemotePlayers - void deSerializePlayers(const std::string &savedir); - -#ifndef SERVER - void updateMeshes(v3s16 blockpos); - void expireMeshes(bool only_daynight_diffed); -#endif void setDayNightRatio(u32 r); u32 getDayNightRatio(); -private: - Map *m_map; - // peer_ids in here should be unique, except that there may be - // many 0s +protected: + // peer_ids in here should be unique, except that there may be many 0s core::list m_players; - // Debug output goes here - std::ostream &m_dout; + // 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); + 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 ¤t_objects, + core::map &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 ¤t_objects, + core::map &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 m_active_objects; + Queue 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); + + /* + 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: + ClientMap *m_map; + scene::ISceneManager *m_smgr; + core::map 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 #include - + // CriticalSection is way faster than the alternative #define JMUTEX_CRITICALSECTION #else // using pthread #include 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/ - 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 #include #include +#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; isetTarget(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 nodehilightbox; f32 mindistance = BS * 1001; - v3s16 pos_i = floatToInt(player_position); + v3s16 pos_i = floatToInt(player_position, BS); /*std::cout<<"pos_i=("< 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::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::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: "; diff --git a/src/map.h b/src/map.h index 60cfd698b..adff82db0 100644 --- a/src/map.h +++ b/src/map.h @@ -33,7 +33,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #endif #include "common_irrlicht.h" -//#include "heightmap.h" #include "mapnode.h" #include "mapblock.h" #include "mapsector.h" @@ -61,7 +60,10 @@ public: { return MAPTYPE_BASE; } - + + /* + Drop (client) or delete (server) the map. + */ virtual void drop() { delete this; @@ -211,19 +213,6 @@ public: void removeNodeAndUpdate(v3s16 p, core::map &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=("<= 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."<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; + + if(m_last_center != center) { - 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=" - < 5.0) - { - m_nearest_unsent_reset_timer = 0; - m_nearest_unsent_d = 0; - //dstream<<"Resetting m_nearest_unsent_d"< 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="<= 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. " - <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"< 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()=" - < &blocks) { - JMutexAutoLock sendinglock(m_blocks_sending_mutex); - JMutexAutoLock sentlock(m_blocks_sent_mutex); - m_nearest_unsent_d = 0; for(core::map::Iterator @@ -964,7 +897,7 @@ u32 PIChecksum(core::list &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); + v3s16 pos = floatToInt(player->getPosition(), BS); + s16 radius = 32; - JMutexAutoLock digmutex(client->m_dig_mutex); - - if(client->m_dig_tool_item == -1) - continue; - - client->m_dig_time_remaining -= dtime; - - if(client->m_dig_time_remaining > 0) - { - client->m_time_from_building.set(0.0); - continue; - } - - v3s16 p_under = client->m_dig_position; + core::map removed_objects; + core::map added_objects; + m_env.getRemovedActiveObjects(pos, radius, + client->m_known_objects, removed_objects); + m_env.getAddedActiveObjects(pos, radius, + client->m_known_objects, added_objects); - // Mandatory parameter; actually used for nothing - core::map modified_blocks; - - u8 material; - - try - { - // 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" - <m_dig_tool_item = -1; - break; - } - } - catch(InvalidPositionException &e) - { - derr_server<<"Server: Not finishing digging: Node not found" - <m_dig_tool_item = -1; - break; - } + // Ignore if nothing happened + if(removed_objects.size() == 0 && added_objects.size() == 0) + continue; - // Create packet - u32 replysize = 8; - SharedBuffer 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); + std::string data_buffer; + + char buf[4]; + + // Handle removed objects + writeU16((u8*)buf, removed_objects.size()); + data_buffer.append(buf, 2); + for(core::map::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()); + + if(obj && obj->m_known_by_count > 0) + obj->m_known_by_count--; + } + + // Handle added objects + writeU16((u8*)buf, added_objects.size()); + data_buffer.append(buf, 2); + for(core::map::Iterator + i = added_objects.getIterator(); + i.atEnd()==false; i++) + { + // 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"<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++; + } + + // Send packet + SharedBuffer 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.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); - } + m_con.Send(client->peer_id, 0, reply, true); - /* - Remove the node - (this takes some time so it is done after the quick stuff) - */ - 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 - { - v.updateAreaWaterPressure(area, m_flow_active_nodes); - } - catch(ProcessingLimitException &e) - { - dstream<<"Processing limit reached (1)"<* > buffered_messages; + + // Get active object messages from environment + for(;;) + { + ActiveObjectMessage aom = m_env.getActiveObjectMessage(); + if(aom.id == 0) + break; + + core::list* message_list = NULL; + core::map* >::Node *n; + n = buffered_messages.find(aom.id); + if(n == NULL) + { + message_list = new core::list; + buffered_messages.insert(aom.id, message_list); + } + else + { + message_list = n->getValue(); + } + message_list->push_back(aom); + } + + // Route data to every client + for(core::map::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* >::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* list = j.getNode()->getValue(); + // Go through every message + for(core::list::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; + } + } + /* + reliable_data and unreliable_data are now ready. + Send them. + */ + if(reliable_data.size() > 0) + { + SharedBuffer 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); + } + if(unreliable_data.size() > 0) + { + SharedBuffer 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); + } + if(reliable_data.size() > 0 || unreliable_data.size() > 0) + { + dstream<<"INFO: Server: Size of object message data: " + <<"reliable: "<* >::Iterator + i = buffered_messages.getIterator(); + i.atEnd()==false; i++) + { + delete i.getNode()->getValue(); + } + } + + /* + 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 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" <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 &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="< + +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 &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 &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