3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "clientserver.h"
24 #include "jmutexautolock.h"
28 #include "mapsector.h"
29 #include "mapblock_mesh.h"
39 QueuedMeshUpdate::QueuedMeshUpdate():
42 ack_block_to_server(false)
46 QueuedMeshUpdate::~QueuedMeshUpdate()
56 MeshUpdateQueue::MeshUpdateQueue()
61 MeshUpdateQueue::~MeshUpdateQueue()
63 JMutexAutoLock lock(m_mutex);
65 core::list<QueuedMeshUpdate*>::Iterator i;
66 for(i=m_queue.begin(); i!=m_queue.end(); i++)
68 QueuedMeshUpdate *q = *i;
74 peer_id=0 adds with nobody to send to
76 void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server)
78 DSTACK(__FUNCTION_NAME);
82 JMutexAutoLock lock(m_mutex);
85 Find if block is already in queue.
86 If it is, update the data and quit.
88 core::list<QueuedMeshUpdate*>::Iterator i;
89 for(i=m_queue.begin(); i!=m_queue.end(); i++)
91 QueuedMeshUpdate *q = *i;
97 if(ack_block_to_server)
98 q->ack_block_to_server = true;
106 QueuedMeshUpdate *q = new QueuedMeshUpdate;
109 q->ack_block_to_server = ack_block_to_server;
110 m_queue.push_back(q);
113 // Returned pointer must be deleted
114 // Returns NULL if queue is empty
115 QueuedMeshUpdate * MeshUpdateQueue::pop()
117 JMutexAutoLock lock(m_mutex);
119 core::list<QueuedMeshUpdate*>::Iterator i = m_queue.begin();
120 if(i == m_queue.end())
122 QueuedMeshUpdate *q = *i;
131 void * MeshUpdateThread::Thread()
135 log_register_thread("MeshUpdateThread");
137 DSTACK(__FUNCTION_NAME);
139 BEGIN_DEBUG_EXCEPTION_HANDLER
143 /*// Wait for output queue to flush.
144 // Allow 2 in queue, this makes less frametime jitter.
145 // Umm actually, there is no much difference
146 if(m_queue_out.size() >= 2)
152 QueuedMeshUpdate *q = m_queue_in.pop();
159 ScopeProfiler sp(g_profiler, "Client: Mesh making");
161 scene::SMesh *mesh_new = NULL;
162 mesh_new = makeMapBlockMesh(q->data);
167 r.ack_block_to_server = q->ack_block_to_server;
169 /*infostream<<"MeshUpdateThread: Processed "
170 <<"("<<q->p.X<<","<<q->p.Y<<","<<q->p.Z<<")"
173 m_queue_out.push_back(r);
178 END_DEBUG_EXCEPTION_HANDLER(errorstream)
184 IrrlichtDevice *device,
185 const char *playername,
186 std::string password,
187 MapDrawControl &control):
188 m_mesh_update_thread(),
190 new ClientMap(this, control,
191 device->getSceneManager()->getRootSceneNode(),
192 device->getSceneManager(), 666),
193 device->getSceneManager()
195 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
197 m_server_ser_ver(SER_FMT_VER_INVALID),
198 m_inventory_updated(false),
201 m_password(password),
202 m_access_denied(false)
204 m_packetcounter_timer = 0.0;
205 //m_delete_unused_sectors_timer = 0.0;
206 m_connection_reinit_timer = 0.0;
207 m_avg_rtt_timer = 0.0;
208 m_playerpos_send_timer = 0.0;
209 m_ignore_damage_timer = 0.0;
211 //m_env_mutex.Init();
212 //m_con_mutex.Init();
214 m_mesh_update_thread.Start();
220 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
222 Player *player = new LocalPlayer();
224 player->updateName(playername);
226 m_env.addPlayer(player);
228 // Initialize player in the inventory context
229 m_inventory_context.current_player = player;
236 //JMutexAutoLock conlock(m_con_mutex); //bulk comment-out
240 m_mesh_update_thread.setRun(false);
241 while(m_mesh_update_thread.IsRunning())
245 void Client::connect(Address address)
247 DSTACK(__FUNCTION_NAME);
248 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
249 m_con.setTimeoutMs(0);
250 m_con.Connect(address);
253 bool Client::connectedAndInitialized()
255 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
257 if(m_con.Connected() == false)
260 if(m_server_ser_ver == SER_FMT_VER_INVALID)
266 void Client::step(float dtime)
268 DSTACK(__FUNCTION_NAME);
274 if(m_ignore_damage_timer > dtime)
275 m_ignore_damage_timer -= dtime;
277 m_ignore_damage_timer = 0.0;
279 //infostream<<"Client steps "<<dtime<<std::endl;
282 //TimeTaker timer("ReceiveAll()", m_device);
288 //TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device);
290 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
291 m_con.RunTimeouts(dtime);
298 float &counter = m_packetcounter_timer;
304 infostream<<"Client packetcounter (20s):"<<std::endl;
305 m_packetcounter.print(infostream);
306 m_packetcounter.clear();
310 // Get connection status
311 bool connected = connectedAndInitialized();
316 Delete unused sectors
318 NOTE: This jams the game for a while because deleting sectors
322 float &counter = m_delete_unused_sectors_timer;
330 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
332 core::list<v3s16> deleted_blocks;
334 float delete_unused_sectors_timeout =
335 g_settings->getFloat("client_delete_unused_sectors_timeout");
337 // Delete sector blocks
338 /*u32 num = m_env.getMap().unloadUnusedData
339 (delete_unused_sectors_timeout,
340 true, &deleted_blocks);*/
342 // Delete whole sectors
343 m_env.getMap().unloadUnusedData
344 (delete_unused_sectors_timeout,
347 if(deleted_blocks.size() > 0)
349 /*infostream<<"Client: Deleted blocks of "<<num
350 <<" unused sectors"<<std::endl;*/
351 /*infostream<<"Client: Deleted "<<num
352 <<" unused sectors"<<std::endl;*/
358 // Env is locked so con can be locked.
359 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
361 core::list<v3s16>::Iterator i = deleted_blocks.begin();
362 core::list<v3s16> sendlist;
365 if(sendlist.size() == 255 || i == deleted_blocks.end())
367 if(sendlist.size() == 0)
376 u32 replysize = 2+1+6*sendlist.size();
377 SharedBuffer<u8> reply(replysize);
378 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
379 reply[2] = sendlist.size();
381 for(core::list<v3s16>::Iterator
382 j = sendlist.begin();
383 j != sendlist.end(); j++)
385 writeV3S16(&reply[2+1+6*k], *j);
388 m_con.Send(PEER_ID_SERVER, 1, reply, true);
390 if(i == deleted_blocks.end())
396 sendlist.push_back(*i);
404 if(connected == false)
406 float &counter = m_connection_reinit_timer;
412 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
414 Player *myplayer = m_env.getLocalPlayer();
415 assert(myplayer != NULL);
417 // Send TOSERVER_INIT
418 // [0] u16 TOSERVER_INIT
419 // [2] u8 SER_FMT_VER_HIGHEST
420 // [3] u8[20] player_name
421 // [23] u8[28] password (new in some version)
422 // [51] u16 client network protocol version (new in some version)
423 SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2);
424 writeU16(&data[0], TOSERVER_INIT);
425 writeU8(&data[2], SER_FMT_VER_HIGHEST);
427 memset((char*)&data[3], 0, PLAYERNAME_SIZE);
428 snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
430 /*infostream<<"Client: sending initial password hash: \""<<m_password<<"\""
433 memset((char*)&data[23], 0, PASSWORD_SIZE);
434 snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
436 // This should be incremented in each version
437 writeU16(&data[51], 3);
439 // Send as unreliable
440 Send(0, data, false);
443 // Not connected, return
448 Do stuff if connected
452 Run Map's timers and unload unused data
454 const float map_timer_and_unload_dtime = 5.25;
455 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
457 ScopeProfiler sp(g_profiler, "Client: map timer and unload");
458 core::list<v3s16> deleted_blocks;
459 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
460 g_settings->getFloat("client_unload_unused_data_timeout"),
463 /*if(deleted_blocks.size() > 0)
464 infostream<<"Client: Unloaded "<<deleted_blocks.size()
465 <<" unused blocks"<<std::endl;*/
469 NOTE: This loop is intentionally iterated the way it is.
472 core::list<v3s16>::Iterator i = deleted_blocks.begin();
473 core::list<v3s16> sendlist;
476 if(sendlist.size() == 255 || i == deleted_blocks.end())
478 if(sendlist.size() == 0)
487 u32 replysize = 2+1+6*sendlist.size();
488 SharedBuffer<u8> reply(replysize);
489 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
490 reply[2] = sendlist.size();
492 for(core::list<v3s16>::Iterator
493 j = sendlist.begin();
494 j != sendlist.end(); j++)
496 writeV3S16(&reply[2+1+6*k], *j);
499 m_con.Send(PEER_ID_SERVER, 1, reply, true);
501 if(i == deleted_blocks.end())
507 sendlist.push_back(*i);
517 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
519 // Control local player (0ms)
520 LocalPlayer *player = m_env.getLocalPlayer();
521 assert(player != NULL);
522 player->applyControl(dtime);
524 //TimeTaker envtimer("env step", m_device);
533 ClientEnvEvent event = m_env.getClientEvent();
534 if(event.type == CEE_NONE)
538 else if(event.type == CEE_PLAYER_DAMAGE)
540 if(m_ignore_damage_timer <= 0)
542 u8 damage = event.player_damage.amount;
545 // Add to ClientEvent queue
547 event.type = CE_PLAYER_DAMAGE;
548 event.player_damage.amount = damage;
549 m_client_event_queue.push_back(event);
559 float &counter = m_avg_rtt_timer;
564 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
565 // connectedAndInitialized() is true, peer exists.
566 con::Peer *peer = m_con.GetPeer(PEER_ID_SERVER);
567 infostream<<"Client: avg_rtt="<<peer->avg_rtt<<std::endl;
572 Send player position to server
575 float &counter = m_playerpos_send_timer;
585 Replace updated meshes
588 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
590 //TimeTaker timer("** Processing mesh update result queue");
593 /*infostream<<"Mesh update result queue size is "
594 <<m_mesh_update_thread.m_queue_out.size()
597 while(m_mesh_update_thread.m_queue_out.size() > 0)
599 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
600 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
603 block->replaceMesh(r.mesh);
605 if(r.ack_block_to_server)
607 /*infostream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
608 <<","<<r.p.Z<<")"<<std::endl;*/
619 u32 replysize = 2+1+6;
620 SharedBuffer<u8> reply(replysize);
621 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
623 writeV3S16(&reply[3], r.p);
625 m_con.Send(PEER_ID_SERVER, 1, reply, true);
631 // Virtual methods from con::PeerHandler
632 void Client::peerAdded(con::Peer *peer)
634 infostream<<"Client::peerAdded(): peer->id="
635 <<peer->id<<std::endl;
637 void Client::deletingPeer(con::Peer *peer, bool timeout)
639 infostream<<"Client::deletingPeer(): "
640 "Server Peer is getting deleted "
641 <<"(timeout="<<timeout<<")"<<std::endl;
644 void Client::ReceiveAll()
646 DSTACK(__FUNCTION_NAME);
652 catch(con::NoIncomingDataException &e)
656 catch(con::InvalidIncomingDataException &e)
658 infostream<<"Client::ReceiveAll(): "
659 "InvalidIncomingDataException: what()="
660 <<e.what()<<std::endl;
665 void Client::Receive()
667 DSTACK(__FUNCTION_NAME);
668 u32 data_maxsize = 200000;
669 Buffer<u8> data(data_maxsize);
673 //TimeTaker t1("con mutex and receive", m_device);
674 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
675 datasize = m_con.Receive(sender_peer_id, *data, data_maxsize);
677 //TimeTaker t1("ProcessData", m_device);
678 ProcessData(*data, datasize, sender_peer_id);
682 sender_peer_id given to this shall be quaranteed to be a valid peer
684 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
686 DSTACK(__FUNCTION_NAME);
688 // Ignore packets that don't even fit a command
691 m_packetcounter.add(60000);
695 ToClientCommand command = (ToClientCommand)readU16(&data[0]);
697 //infostream<<"Client: received command="<<command<<std::endl;
698 m_packetcounter.add((u16)command);
701 If this check is removed, be sure to change the queue
702 system to know the ids
704 if(sender_peer_id != PEER_ID_SERVER)
706 infostream<<"Client::ProcessData(): Discarding data not "
707 "coming from server: peer_id="<<sender_peer_id
714 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
715 // All data is coming from the server
716 // PeerNotFoundException is handled by caller.
717 peer = m_con.GetPeer(PEER_ID_SERVER);
720 u8 ser_version = m_server_ser_ver;
722 //infostream<<"Client received command="<<(int)command<<std::endl;
724 if(command == TOCLIENT_INIT)
729 u8 deployed = data[2];
731 infostream<<"Client: TOCLIENT_INIT received with "
732 "deployed="<<((int)deployed&0xff)<<std::endl;
734 if(deployed < SER_FMT_VER_LOWEST
735 || deployed > SER_FMT_VER_HIGHEST)
737 infostream<<"Client: TOCLIENT_INIT: Server sent "
738 <<"unsupported ser_fmt_ver"<<std::endl;
742 m_server_ser_ver = deployed;
744 // Get player position
745 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
746 if(datasize >= 2+1+6)
747 playerpos_s16 = readV3S16(&data[2+1]);
748 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
751 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
753 // Set player position
754 Player *player = m_env.getLocalPlayer();
755 assert(player != NULL);
756 player->setPosition(playerpos_f);
759 if(datasize >= 2+1+6+8)
762 m_map_seed = readU64(&data[2+1+6]);
763 infostream<<"Client: received map seed: "<<m_map_seed<<std::endl;
768 SharedBuffer<u8> reply(replysize);
769 writeU16(&reply[0], TOSERVER_INIT2);
771 m_con.Send(PEER_ID_SERVER, 1, reply, true);
776 if(command == TOCLIENT_ACCESS_DENIED)
778 // The server didn't like our password. Note, this needs
779 // to be processed even if the serialisation format has
780 // not been agreed yet, the same as TOCLIENT_INIT.
781 m_access_denied = true;
782 m_access_denied_reason = L"Unknown";
785 std::string datastring((char*)&data[2], datasize-2);
786 std::istringstream is(datastring, std::ios_base::binary);
787 m_access_denied_reason = deSerializeWideString(is);
792 if(ser_version == SER_FMT_VER_INVALID)
794 infostream<<"Client: Server serialization"
795 " format invalid or not initialized."
796 " Skipping incoming command="<<command<<std::endl;
800 // Just here to avoid putting the two if's together when
801 // making some copypasta
804 if(command == TOCLIENT_REMOVENODE)
809 p.X = readS16(&data[2]);
810 p.Y = readS16(&data[4]);
811 p.Z = readS16(&data[6]);
813 //TimeTaker t1("TOCLIENT_REMOVENODE");
815 // This will clear the cracking animation after digging
816 ((ClientMap&)m_env.getMap()).clearTempMod(p);
820 else if(command == TOCLIENT_ADDNODE)
822 if(datasize < 8 + MapNode::serializedLength(ser_version))
826 p.X = readS16(&data[2]);
827 p.Y = readS16(&data[4]);
828 p.Z = readS16(&data[6]);
830 //TimeTaker t1("TOCLIENT_ADDNODE");
833 n.deSerialize(&data[8], ser_version);
837 else if(command == TOCLIENT_BLOCKDATA)
839 // Ignore too small packet
844 p.X = readS16(&data[2]);
845 p.Y = readS16(&data[4]);
846 p.Z = readS16(&data[6]);
848 /*infostream<<"Client: Thread: BLOCKDATA for ("
849 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
850 /*infostream<<"Client: Thread: BLOCKDATA for ("
851 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
853 std::string datastring((char*)&data[8], datasize-8);
854 std::istringstream istr(datastring, std::ios_base::binary);
860 sector = m_env.getMap().emergeSector(p2d);
862 assert(sector->getPos() == p2d);
864 //TimeTaker timer("MapBlock deSerialize");
867 block = sector->getBlockNoCreateNoEx(p.Y);
871 Update an existing block
873 //infostream<<"Updating"<<std::endl;
874 block->deSerialize(istr, ser_version);
881 //infostream<<"Creating new"<<std::endl;
882 block = new MapBlock(&m_env.getMap(), p);
883 block->deSerialize(istr, ser_version);
884 sector->insertBlock(block);
888 mod.type = NODEMOD_CHANGECONTENT;
889 mod.param = CONTENT_MESE;
890 block->setTempMod(v3s16(8,10,8), mod);
891 block->setTempMod(v3s16(8,9,8), mod);
892 block->setTempMod(v3s16(8,8,8), mod);
893 block->setTempMod(v3s16(8,7,8), mod);
894 block->setTempMod(v3s16(8,6,8), mod);*/
908 u32 replysize = 2+1+6;
909 SharedBuffer<u8> reply(replysize);
910 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
912 writeV3S16(&reply[3], p);
914 m_con.Send(PEER_ID_SERVER, 1, reply, true);
918 Update Mesh of this block and blocks at x-, y- and z-.
919 Environment should not be locked as it interlocks with the
920 main thread, from which is will want to retrieve textures.
923 //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
925 Add it to mesh update queue and set it to be acknowledged after update.
927 //infostream<<"Adding mesh update task for received block"<<std::endl;
928 addUpdateMeshTaskWithEdge(p, true);
930 else if(command == TOCLIENT_PLAYERPOS)
932 infostream<<"Received deprecated TOCLIENT_PLAYERPOS"
936 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
937 our_peer_id = m_con.GetPeerID();
939 // Cancel if we don't have a peer id
940 if(our_peer_id == PEER_ID_INEXISTENT){
941 infostream<<"TOCLIENT_PLAYERPOS cancelled: "
948 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
950 u32 player_size = 2+12+12+4+4;
952 u32 player_count = (datasize-2) / player_size;
954 for(u32 i=0; i<player_count; i++)
956 u16 peer_id = readU16(&data[start]);
958 Player *player = m_env.getPlayer(peer_id);
960 // Skip if player doesn't exist
963 start += player_size;
967 // Skip if player is local player
968 if(player->isLocal())
970 start += player_size;
974 v3s32 ps = readV3S32(&data[start+2]);
975 v3s32 ss = readV3S32(&data[start+2+12]);
976 s32 pitch_i = readS32(&data[start+2+12+12]);
977 s32 yaw_i = readS32(&data[start+2+12+12+4]);
978 /*infostream<<"Client: got "
979 <<"pitch_i="<<pitch_i
980 <<" yaw_i="<<yaw_i<<std::endl;*/
981 f32 pitch = (f32)pitch_i / 100.0;
982 f32 yaw = (f32)yaw_i / 100.0;
983 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
984 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
985 player->setPosition(position);
986 player->setSpeed(speed);
987 player->setPitch(pitch);
990 /*infostream<<"Client: player "<<peer_id
992 <<" yaw="<<yaw<<std::endl;*/
994 start += player_size;
998 else if(command == TOCLIENT_PLAYERINFO)
1002 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1003 our_peer_id = m_con.GetPeerID();
1005 // Cancel if we don't have a peer id
1006 if(our_peer_id == PEER_ID_INEXISTENT){
1007 infostream<<"TOCLIENT_PLAYERINFO cancelled: "
1008 "we have no peer id"
1013 //infostream<<"Client: Server reports players:"<<std::endl;
1016 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1018 u32 item_size = 2+PLAYERNAME_SIZE;
1019 u32 player_count = (datasize-2) / item_size;
1022 core::list<u16> players_alive;
1023 for(u32 i=0; i<player_count; i++)
1025 // Make sure the name ends in '\0'
1026 data[start+2+20-1] = 0;
1028 u16 peer_id = readU16(&data[start]);
1030 players_alive.push_back(peer_id);
1032 /*infostream<<"peer_id="<<peer_id
1033 <<" name="<<((char*)&data[start+2])<<std::endl;*/
1035 // Don't update the info of the local player
1036 if(peer_id == our_peer_id)
1042 Player *player = m_env.getPlayer(peer_id);
1044 // Create a player if it doesn't exist
1047 player = new RemotePlayer(
1048 m_device->getSceneManager()->getRootSceneNode(),
1051 player->peer_id = peer_id;
1052 m_env.addPlayer(player);
1053 infostream<<"Client: Adding new player "
1054 <<peer_id<<std::endl;
1057 player->updateName((char*)&data[start+2]);
1063 Remove those players from the environment that
1064 weren't listed by the server.
1066 //infostream<<"Removing dead players"<<std::endl;
1067 core::list<Player*> players = m_env.getPlayers();
1068 core::list<Player*>::Iterator ip;
1069 for(ip=players.begin(); ip!=players.end(); ip++)
1071 // Ingore local player
1072 if((*ip)->isLocal())
1075 // Warn about a special case
1076 if((*ip)->peer_id == 0)
1078 infostream<<"Client: Removing "
1079 "dead player with id=0"<<std::endl;
1082 bool is_alive = false;
1083 core::list<u16>::Iterator i;
1084 for(i=players_alive.begin(); i!=players_alive.end(); i++)
1086 if((*ip)->peer_id == *i)
1092 /*infostream<<"peer_id="<<((*ip)->peer_id)
1093 <<" is_alive="<<is_alive<<std::endl;*/
1096 infostream<<"Removing dead player "<<(*ip)->peer_id
1098 m_env.removePlayer((*ip)->peer_id);
1102 else if(command == TOCLIENT_SECTORMETA)
1104 infostream<<"Client received DEPRECATED TOCLIENT_SECTORMETA"<<std::endl;
1109 [3...] v2s16 pos + sector metadata
1114 //infostream<<"Client received TOCLIENT_SECTORMETA"<<std::endl;
1117 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1119 std::string datastring((char*)&data[2], datasize-2);
1120 std::istringstream is(datastring, std::ios_base::binary);
1124 is.read((char*)buf, 1);
1125 u16 sector_count = readU8(buf);
1127 //infostream<<"sector_count="<<sector_count<<std::endl;
1129 for(u16 i=0; i<sector_count; i++)
1132 is.read((char*)buf, 4);
1133 v2s16 pos = readV2S16(buf);
1134 /*infostream<<"Client: deserializing sector at "
1135 <<"("<<pos.X<<","<<pos.Y<<")"<<std::endl;*/
1137 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
1138 ((ClientMap&)m_env.getMap()).deSerializeSector(pos, is);
1143 else if(command == TOCLIENT_INVENTORY)
1148 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
1151 //TimeTaker t2("mutex locking", m_device);
1152 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1155 //TimeTaker t3("istringstream init", m_device);
1156 std::string datastring((char*)&data[2], datasize-2);
1157 std::istringstream is(datastring, std::ios_base::binary);
1160 //m_env.printPlayers(infostream);
1162 //TimeTaker t4("player get", m_device);
1163 Player *player = m_env.getLocalPlayer();
1164 assert(player != NULL);
1167 //TimeTaker t1("inventory.deSerialize()", m_device);
1168 player->inventory.deSerialize(is);
1171 m_inventory_updated = true;
1173 //infostream<<"Client got player inventory:"<<std::endl;
1174 //player->inventory.print(infostream);
1178 else if(command == TOCLIENT_OBJECTDATA)
1180 // Strip command word and create a stringstream
1181 std::string datastring((char*)&data[2], datasize-2);
1182 std::istringstream is(datastring, std::ios_base::binary);
1190 is.read((char*)buf, 2);
1191 u16 playercount = readU16(buf);
1193 for(u16 i=0; i<playercount; i++)
1195 is.read((char*)buf, 2);
1196 u16 peer_id = readU16(buf);
1197 is.read((char*)buf, 12);
1198 v3s32 p_i = readV3S32(buf);
1199 is.read((char*)buf, 12);
1200 v3s32 s_i = readV3S32(buf);
1201 is.read((char*)buf, 4);
1202 s32 pitch_i = readS32(buf);
1203 is.read((char*)buf, 4);
1204 s32 yaw_i = readS32(buf);
1206 Player *player = m_env.getPlayer(peer_id);
1208 // Skip if player doesn't exist
1214 // Skip if player is local player
1215 if(player->isLocal())
1220 f32 pitch = (f32)pitch_i / 100.0;
1221 f32 yaw = (f32)yaw_i / 100.0;
1222 v3f position((f32)p_i.X/100., (f32)p_i.Y/100., (f32)p_i.Z/100.);
1223 v3f speed((f32)s_i.X/100., (f32)s_i.Y/100., (f32)s_i.Z/100.);
1225 player->setPosition(position);
1226 player->setSpeed(speed);
1227 player->setPitch(pitch);
1228 player->setYaw(yaw);
1233 NOTE: Deprecated stuff
1236 // Read active block count
1237 u16 blockcount = readU16(is);
1238 if(blockcount != 0){
1239 infostream<<"TOCLIENT_OBJECTDATA: blockcount != 0 "
1240 "not supported"<<std::endl;
1244 else if(command == TOCLIENT_TIME_OF_DAY)
1249 u16 time_of_day = readU16(&data[2]);
1250 time_of_day = time_of_day % 24000;
1251 //infostream<<"Client: time_of_day="<<time_of_day<<std::endl;
1259 m_env.setTimeOfDay(time_of_day);
1261 u32 dr = m_env.getDayNightRatio();
1263 infostream<<"Client: time_of_day="<<time_of_day
1269 else if(command == TOCLIENT_CHAT_MESSAGE)
1277 std::string datastring((char*)&data[2], datasize-2);
1278 std::istringstream is(datastring, std::ios_base::binary);
1281 is.read((char*)buf, 2);
1282 u16 len = readU16(buf);
1284 std::wstring message;
1285 for(u16 i=0; i<len; i++)
1287 is.read((char*)buf, 2);
1288 message += (wchar_t)readU16(buf);
1291 /*infostream<<"Client received chat message: "
1292 <<wide_to_narrow(message)<<std::endl;*/
1294 m_chat_queue.push_back(message);
1296 else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1298 //if(g_settings->getBool("enable_experimental"))
1302 u16 count of removed objects
1303 for all removed objects {
1306 u16 count of added objects
1307 for all added objects {
1310 u32 initialization data length
1311 string initialization data
1316 // Get all data except the command number
1317 std::string datastring((char*)&data[2], datasize-2);
1318 // Throw them in an istringstream
1319 std::istringstream is(datastring, std::ios_base::binary);
1323 // Read removed objects
1325 u16 removed_count = readU16((u8*)buf);
1326 for(u16 i=0; i<removed_count; i++)
1329 u16 id = readU16((u8*)buf);
1332 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1333 m_env.removeActiveObject(id);
1337 // Read added objects
1339 u16 added_count = readU16((u8*)buf);
1340 for(u16 i=0; i<added_count; i++)
1343 u16 id = readU16((u8*)buf);
1345 u8 type = readU8((u8*)buf);
1346 std::string data = deSerializeLongString(is);
1349 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1350 m_env.addActiveObject(id, type, data);
1355 else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1357 //if(g_settings->getBool("enable_experimental"))
1369 // Get all data except the command number
1370 std::string datastring((char*)&data[2], datasize-2);
1371 // Throw them in an istringstream
1372 std::istringstream is(datastring, std::ios_base::binary);
1374 while(is.eof() == false)
1378 u16 id = readU16((u8*)buf);
1382 u16 message_size = readU16((u8*)buf);
1383 std::string message;
1384 message.reserve(message_size);
1385 for(u16 i=0; i<message_size; i++)
1388 message.append(buf, 1);
1390 // Pass on to the environment
1392 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1393 m_env.processActiveObjectMessage(id, message);
1398 else if(command == TOCLIENT_HP)
1400 std::string datastring((char*)&data[2], datasize-2);
1401 std::istringstream is(datastring, std::ios_base::binary);
1402 Player *player = m_env.getLocalPlayer();
1403 assert(player != NULL);
1407 else if(command == TOCLIENT_MOVE_PLAYER)
1409 std::string datastring((char*)&data[2], datasize-2);
1410 std::istringstream is(datastring, std::ios_base::binary);
1411 Player *player = m_env.getLocalPlayer();
1412 assert(player != NULL);
1413 v3f pos = readV3F1000(is);
1414 f32 pitch = readF1000(is);
1415 f32 yaw = readF1000(is);
1416 player->setPosition(pos);
1417 /*player->setPitch(pitch);
1418 player->setYaw(yaw);*/
1420 infostream<<"Client got TOCLIENT_MOVE_PLAYER"
1421 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1427 Add to ClientEvent queue.
1428 This has to be sent to the main program because otherwise
1429 it would just force the pitch and yaw values to whatever
1430 the camera points to.
1433 event.type = CE_PLAYER_FORCE_MOVE;
1434 event.player_force_move.pitch = pitch;
1435 event.player_force_move.yaw = yaw;
1436 m_client_event_queue.push_back(event);
1438 // Ignore damage for a few seconds, so that the player doesn't
1439 // get damage from falling on ground
1440 m_ignore_damage_timer = 3.0;
1442 else if(command == TOCLIENT_PLAYERITEM)
1444 std::string datastring((char*)&data[2], datasize-2);
1445 std::istringstream is(datastring, std::ios_base::binary);
1447 u16 count = readU16(is);
1449 for (u16 i = 0; i < count; ++i) {
1450 u16 peer_id = readU16(is);
1451 Player *player = m_env.getPlayer(peer_id);
1455 infostream<<"Client: ignoring player item "
1456 << deSerializeString(is)
1457 << " for non-existing peer id " << peer_id
1460 } else if (player->isLocal()) {
1461 infostream<<"Client: ignoring player item "
1462 << deSerializeString(is)
1463 << " for local player" << std::endl;
1466 InventoryList *inv = player->inventory.getList("main");
1467 std::string itemstring(deSerializeString(is));
1468 if (itemstring.empty()) {
1471 <<"Client: empty player item for peer "
1472 << peer_id << std::endl;
1474 std::istringstream iss(itemstring);
1475 delete inv->changeItem(0, InventoryItem::deSerialize(iss));
1476 infostream<<"Client: player item for peer " << peer_id << ": ";
1477 player->getWieldItem()->serialize(infostream);
1478 infostream<<std::endl;
1483 else if(command == TOCLIENT_DEATHSCREEN)
1485 std::string datastring((char*)&data[2], datasize-2);
1486 std::istringstream is(datastring, std::ios_base::binary);
1488 bool set_camera_point_target = readU8(is);
1489 v3f camera_point_target = readV3F1000(is);
1492 event.type = CE_DEATHSCREEN;
1493 event.deathscreen.set_camera_point_target = set_camera_point_target;
1494 event.deathscreen.camera_point_target_x = camera_point_target.X;
1495 event.deathscreen.camera_point_target_y = camera_point_target.Y;
1496 event.deathscreen.camera_point_target_z = camera_point_target.Z;
1497 m_client_event_queue.push_back(event);
1501 infostream<<"Client: Ignoring unknown command "
1502 <<command<<std::endl;
1506 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1508 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1509 m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1512 void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
1513 v3s16 nodepos_oversurface, u16 item)
1515 if(connectedAndInitialized() == false){
1516 infostream<<"Client::groundAction() "
1517 "cancelled (not connected)"
1526 [3] v3s16 nodepos_undersurface
1527 [9] v3s16 nodepos_abovesurface
1532 2: stop digging (all parameters ignored)
1533 3: digging completed
1535 u8 datasize = 2 + 1 + 6 + 6 + 2;
1536 SharedBuffer<u8> data(datasize);
1537 writeU16(&data[0], TOSERVER_GROUND_ACTION);
1538 writeU8(&data[2], action);
1539 writeV3S16(&data[3], nodepos_undersurface);
1540 writeV3S16(&data[9], nodepos_oversurface);
1541 writeU16(&data[15], item);
1542 Send(0, data, true);
1545 void Client::clickActiveObject(u8 button, u16 id, u16 item_i)
1547 if(connectedAndInitialized() == false){
1548 infostream<<"Client::clickActiveObject() "
1549 "cancelled (not connected)"
1554 Player *player = m_env.getLocalPlayer();
1558 ClientActiveObject *obj = m_env.getActiveObject(id);
1561 ToolItem *titem = NULL;
1562 std::string toolname = "";
1564 InventoryList *mlist = player->inventory.getList("main");
1567 InventoryItem *item = mlist->getItem(item_i);
1568 if(item && (std::string)item->getName() == "ToolItem")
1570 titem = (ToolItem*)item;
1571 toolname = titem->getToolName();
1575 v3f playerpos = player->getPosition();
1576 v3f objpos = obj->getPosition();
1577 v3f dir = (objpos - playerpos).normalize();
1579 bool disable_send = obj->directReportPunch(toolname, dir);
1589 [2] u8 button (0=left, 1=right)
1593 u8 datasize = 2 + 1 + 6 + 2 + 2;
1594 SharedBuffer<u8> data(datasize);
1595 writeU16(&data[0], TOSERVER_CLICK_ACTIVEOBJECT);
1596 writeU8(&data[2], button);
1597 writeU16(&data[3], id);
1598 writeU16(&data[5], item_i);
1599 Send(0, data, true);
1602 void Client::sendSignNodeText(v3s16 p, std::string text)
1610 std::ostringstream os(std::ios_base::binary);
1614 writeU16(buf, TOSERVER_SIGNNODETEXT);
1615 os.write((char*)buf, 2);
1619 os.write((char*)buf, 6);
1621 u16 textlen = text.size();
1622 // Write text length
1623 writeS16(buf, textlen);
1624 os.write((char*)buf, 2);
1627 os.write((char*)text.c_str(), textlen);
1630 std::string s = os.str();
1631 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1633 Send(0, data, true);
1636 void Client::sendInventoryAction(InventoryAction *a)
1638 std::ostringstream os(std::ios_base::binary);
1642 writeU16(buf, TOSERVER_INVENTORY_ACTION);
1643 os.write((char*)buf, 2);
1648 std::string s = os.str();
1649 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1651 Send(0, data, true);
1654 void Client::sendChatMessage(const std::wstring &message)
1656 std::ostringstream os(std::ios_base::binary);
1660 writeU16(buf, TOSERVER_CHAT_MESSAGE);
1661 os.write((char*)buf, 2);
1664 writeU16(buf, message.size());
1665 os.write((char*)buf, 2);
1668 for(u32 i=0; i<message.size(); i++)
1672 os.write((char*)buf, 2);
1676 std::string s = os.str();
1677 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1679 Send(0, data, true);
1682 void Client::sendChangePassword(const std::wstring oldpassword,
1683 const std::wstring newpassword)
1685 Player *player = m_env.getLocalPlayer();
1689 std::string playername = player->getName();
1690 std::string oldpwd = translatePassword(playername, oldpassword);
1691 std::string newpwd = translatePassword(playername, newpassword);
1693 std::ostringstream os(std::ios_base::binary);
1694 u8 buf[2+PASSWORD_SIZE*2];
1696 [0] u16 TOSERVER_PASSWORD
1697 [2] u8[28] old password
1698 [30] u8[28] new password
1701 writeU16(buf, TOSERVER_PASSWORD);
1702 for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1704 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1705 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1707 buf[2+PASSWORD_SIZE-1] = 0;
1708 buf[30+PASSWORD_SIZE-1] = 0;
1709 os.write((char*)buf, 2+PASSWORD_SIZE*2);
1712 std::string s = os.str();
1713 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1715 Send(0, data, true);
1719 void Client::sendDamage(u8 damage)
1721 DSTACK(__FUNCTION_NAME);
1722 std::ostringstream os(std::ios_base::binary);
1724 writeU16(os, TOSERVER_DAMAGE);
1725 writeU8(os, damage);
1728 std::string s = os.str();
1729 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1731 Send(0, data, true);
1734 void Client::sendRespawn()
1736 DSTACK(__FUNCTION_NAME);
1737 std::ostringstream os(std::ios_base::binary);
1739 writeU16(os, TOSERVER_RESPAWN);
1742 std::string s = os.str();
1743 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1745 Send(0, data, true);
1748 void Client::sendPlayerPos()
1750 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1752 Player *myplayer = m_env.getLocalPlayer();
1753 if(myplayer == NULL)
1758 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1759 our_peer_id = m_con.GetPeerID();
1762 // Set peer id if not set already
1763 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1764 myplayer->peer_id = our_peer_id;
1765 // Check that an existing peer_id is the same as the connection's
1766 assert(myplayer->peer_id == our_peer_id);
1768 v3f pf = myplayer->getPosition();
1769 v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1770 v3f sf = myplayer->getSpeed();
1771 v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1772 s32 pitch = myplayer->getPitch() * 100;
1773 s32 yaw = myplayer->getYaw() * 100;
1778 [2] v3s32 position*100
1779 [2+12] v3s32 speed*100
1780 [2+12+12] s32 pitch*100
1781 [2+12+12+4] s32 yaw*100
1784 SharedBuffer<u8> data(2+12+12+4+4);
1785 writeU16(&data[0], TOSERVER_PLAYERPOS);
1786 writeV3S32(&data[2], position);
1787 writeV3S32(&data[2+12], speed);
1788 writeS32(&data[2+12+12], pitch);
1789 writeS32(&data[2+12+12+4], yaw);
1791 // Send as unreliable
1792 Send(0, data, false);
1795 void Client::sendPlayerItem(u16 item)
1797 Player *myplayer = m_env.getLocalPlayer();
1798 if(myplayer == NULL)
1801 u16 our_peer_id = m_con.GetPeerID();
1803 // Set peer id if not set already
1804 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1805 myplayer->peer_id = our_peer_id;
1806 // Check that an existing peer_id is the same as the connection's
1807 assert(myplayer->peer_id == our_peer_id);
1809 SharedBuffer<u8> data(2+2);
1810 writeU16(&data[0], TOSERVER_PLAYERITEM);
1811 writeU16(&data[2], item);
1814 Send(0, data, true);
1817 void Client::removeNode(v3s16 p)
1819 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1821 core::map<v3s16, MapBlock*> modified_blocks;
1825 //TimeTaker t("removeNodeAndUpdate", m_device);
1826 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1828 catch(InvalidPositionException &e)
1832 for(core::map<v3s16, MapBlock * >::Iterator
1833 i = modified_blocks.getIterator();
1834 i.atEnd() == false; i++)
1836 v3s16 p = i.getNode()->getKey();
1837 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1838 addUpdateMeshTaskWithEdge(p);
1842 void Client::addNode(v3s16 p, MapNode n)
1844 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1846 TimeTaker timer1("Client::addNode()");
1848 core::map<v3s16, MapBlock*> modified_blocks;
1852 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1853 std::string st = std::string("");
1854 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st);
1856 catch(InvalidPositionException &e)
1859 //TimeTaker timer2("Client::addNode(): updateMeshes");
1861 for(core::map<v3s16, MapBlock * >::Iterator
1862 i = modified_blocks.getIterator();
1863 i.atEnd() == false; i++)
1865 v3s16 p = i.getNode()->getKey();
1866 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1867 addUpdateMeshTaskWithEdge(p);
1871 void Client::updateCamera(v3f pos, v3f dir, f32 fov)
1873 m_env.getClientMap().updateCamera(pos, dir, fov);
1876 void Client::renderPostFx()
1878 m_env.getClientMap().renderPostFx();
1881 MapNode Client::getNode(v3s16 p)
1883 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1884 return m_env.getMap().getNode(p);
1887 NodeMetadata* Client::getNodeMetadata(v3s16 p)
1889 return m_env.getMap().getNodeMetadata(p);
1892 LocalPlayer* Client::getLocalPlayer()
1894 return m_env.getLocalPlayer();
1897 void Client::setPlayerControl(PlayerControl &control)
1899 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1900 LocalPlayer *player = m_env.getLocalPlayer();
1901 assert(player != NULL);
1902 player->control = control;
1905 void Client::selectPlayerItem(u16 item)
1907 LocalPlayer *player = m_env.getLocalPlayer();
1908 assert(player != NULL);
1910 player->wieldItem(item);
1912 sendPlayerItem(item);
1915 // Returns true if the inventory of the local player has been
1916 // updated from the server. If it is true, it is set to false.
1917 bool Client::getLocalInventoryUpdated()
1919 // m_inventory_updated is behind envlock
1920 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1921 bool updated = m_inventory_updated;
1922 m_inventory_updated = false;
1926 // Copies the inventory of the local player to parameter
1927 void Client::getLocalInventory(Inventory &dst)
1929 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1930 Player *player = m_env.getLocalPlayer();
1931 assert(player != NULL);
1932 dst = player->inventory;
1935 InventoryContext *Client::getInventoryContext()
1937 return &m_inventory_context;
1940 Inventory* Client::getInventory(InventoryContext *c, std::string id)
1942 if(id == "current_player")
1944 assert(c->current_player);
1945 return &(c->current_player->inventory);
1949 std::string id0 = fn.next(":");
1951 if(id0 == "nodemeta")
1954 p.X = stoi(fn.next(","));
1955 p.Y = stoi(fn.next(","));
1956 p.Z = stoi(fn.next(","));
1957 NodeMetadata* meta = getNodeMetadata(p);
1959 return meta->getInventory();
1960 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
1961 <<"no metadata found"<<std::endl;
1965 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
1968 void Client::inventoryAction(InventoryAction *a)
1970 sendInventoryAction(a);
1973 ClientActiveObject * Client::getSelectedActiveObject(
1975 v3f from_pos_f_on_map,
1976 core::line3d<f32> shootline_on_map
1979 core::array<DistanceSortedActiveObject> objects;
1981 m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
1983 //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
1986 // After this, the closest object is the first in the array.
1989 for(u32 i=0; i<objects.size(); i++)
1991 ClientActiveObject *obj = objects[i].obj;
1993 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
1994 if(selection_box == NULL)
1997 v3f pos = obj->getPosition();
1999 core::aabbox3d<f32> offsetted_box(
2000 selection_box->MinEdge + pos,
2001 selection_box->MaxEdge + pos
2004 if(offsetted_box.intersectsWithLine(shootline_on_map))
2006 //infostream<<"Returning selected object"<<std::endl;
2011 //infostream<<"No object selected; returning NULL."<<std::endl;
2015 void Client::printDebugInfo(std::ostream &os)
2017 //JMutexAutoLock lock1(m_fetchblock_mutex);
2018 /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2020 os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2021 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2022 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2026 u32 Client::getDayNightRatio()
2028 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2029 return m_env.getDayNightRatio();
2034 Player *player = m_env.getLocalPlayer();
2035 assert(player != NULL);
2039 void Client::setTempMod(v3s16 p, NodeMod mod)
2041 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2042 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2044 core::map<v3s16, MapBlock*> affected_blocks;
2045 ((ClientMap&)m_env.getMap()).setTempMod(p, mod,
2048 for(core::map<v3s16, MapBlock*>::Iterator
2049 i = affected_blocks.getIterator();
2050 i.atEnd() == false; i++)
2052 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2056 void Client::clearTempMod(v3s16 p)
2058 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2059 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2061 core::map<v3s16, MapBlock*> affected_blocks;
2062 ((ClientMap&)m_env.getMap()).clearTempMod(p,
2065 for(core::map<v3s16, MapBlock*>::Iterator
2066 i = affected_blocks.getIterator();
2067 i.atEnd() == false; i++)
2069 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2073 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
2075 /*infostream<<"Client::addUpdateMeshTask(): "
2076 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2079 MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2084 Create a task to update the mesh of the block
2087 MeshMakeData *data = new MeshMakeData;
2090 //TimeTaker timer("data fill");
2092 // Debug: 1-6ms, avg=2ms
2093 data->fill(getDayNightRatio(), b);
2097 //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2099 // Add task to queue
2100 m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server);
2102 /*infostream<<"Mesh update input queue size is "
2103 <<m_mesh_update_thread.m_queue_in.size()
2107 // Temporary test: make mesh directly in here
2109 //TimeTaker timer("make mesh");
2111 scene::SMesh *mesh_new = NULL;
2112 mesh_new = makeMapBlockMesh(data);
2113 b->replaceMesh(mesh_new);
2119 Mark mesh as non-expired at this point so that it can already
2120 be marked as expired again if the data changes
2122 b->setMeshExpired(false);
2125 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
2129 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2130 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2135 v3s16 p = blockpos + v3s16(0,0,0);
2136 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2137 addUpdateMeshTask(p, ack_to_server);
2139 catch(InvalidPositionException &e){}
2142 v3s16 p = blockpos + v3s16(-1,0,0);
2143 addUpdateMeshTask(p);
2145 catch(InvalidPositionException &e){}
2147 v3s16 p = blockpos + v3s16(0,-1,0);
2148 addUpdateMeshTask(p);
2150 catch(InvalidPositionException &e){}
2152 v3s16 p = blockpos + v3s16(0,0,-1);
2153 addUpdateMeshTask(p);
2155 catch(InvalidPositionException &e){}
2158 ClientEvent Client::getClientEvent()
2160 if(m_client_event_queue.size() == 0)
2163 event.type = CE_NONE;
2166 return m_client_event_queue.pop_front();
2169 float Client::getRTT(void)
2171 con::Peer *peer = m_con.GetPeerNoEx(PEER_ID_SERVER);
2174 return peer->avg_rtt;