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"
34 #include "nodemetadata.h"
37 #include <IFileSystem.h>
43 QueuedMeshUpdate::QueuedMeshUpdate():
46 ack_block_to_server(false)
50 QueuedMeshUpdate::~QueuedMeshUpdate()
60 MeshUpdateQueue::MeshUpdateQueue()
65 MeshUpdateQueue::~MeshUpdateQueue()
67 JMutexAutoLock lock(m_mutex);
69 core::list<QueuedMeshUpdate*>::Iterator i;
70 for(i=m_queue.begin(); i!=m_queue.end(); i++)
72 QueuedMeshUpdate *q = *i;
78 peer_id=0 adds with nobody to send to
80 void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server)
82 DSTACK(__FUNCTION_NAME);
86 JMutexAutoLock lock(m_mutex);
89 Find if block is already in queue.
90 If it is, update the data and quit.
92 core::list<QueuedMeshUpdate*>::Iterator i;
93 for(i=m_queue.begin(); i!=m_queue.end(); i++)
95 QueuedMeshUpdate *q = *i;
101 if(ack_block_to_server)
102 q->ack_block_to_server = true;
110 QueuedMeshUpdate *q = new QueuedMeshUpdate;
113 q->ack_block_to_server = ack_block_to_server;
114 m_queue.push_back(q);
117 // Returned pointer must be deleted
118 // Returns NULL if queue is empty
119 QueuedMeshUpdate * MeshUpdateQueue::pop()
121 JMutexAutoLock lock(m_mutex);
123 core::list<QueuedMeshUpdate*>::Iterator i = m_queue.begin();
124 if(i == m_queue.end())
126 QueuedMeshUpdate *q = *i;
135 void * MeshUpdateThread::Thread()
139 log_register_thread("MeshUpdateThread");
141 DSTACK(__FUNCTION_NAME);
143 BEGIN_DEBUG_EXCEPTION_HANDLER
147 /*// Wait for output queue to flush.
148 // Allow 2 in queue, this makes less frametime jitter.
149 // Umm actually, there is no much difference
150 if(m_queue_out.size() >= 2)
156 QueuedMeshUpdate *q = m_queue_in.pop();
163 ScopeProfiler sp(g_profiler, "Client: Mesh making");
165 scene::SMesh *mesh_new = NULL;
166 mesh_new = makeMapBlockMesh(q->data, m_gamedef);
171 r.ack_block_to_server = q->ack_block_to_server;
173 /*infostream<<"MeshUpdateThread: Processed "
174 <<"("<<q->p.X<<","<<q->p.Y<<","<<q->p.Z<<")"
177 m_queue_out.push_back(r);
182 END_DEBUG_EXCEPTION_HANDLER(errorstream)
188 IrrlichtDevice *device,
189 const char *playername,
190 std::string password,
191 MapDrawControl &control,
192 IWritableTextureSource *tsrc,
193 IWritableToolDefManager *tooldef,
194 IWritableNodeDefManager *nodedef
199 m_mesh_update_thread(this),
201 new ClientMap(this, this, control,
202 device->getSceneManager()->getRootSceneNode(),
203 device->getSceneManager(), 666),
204 device->getSceneManager(),
207 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
209 m_server_ser_ver(SER_FMT_VER_INVALID),
210 m_inventory_updated(false),
213 m_password(password),
214 m_access_denied(false),
215 m_texture_receive_progress(0),
216 m_textures_received(false),
217 m_tooldef_received(false),
218 m_nodedef_received(false)
220 m_packetcounter_timer = 0.0;
221 //m_delete_unused_sectors_timer = 0.0;
222 m_connection_reinit_timer = 0.0;
223 m_avg_rtt_timer = 0.0;
224 m_playerpos_send_timer = 0.0;
225 m_ignore_damage_timer = 0.0;
227 // Build main texture atlas, now that the GameDef exists (that is, us)
228 if(g_settings->getBool("enable_texture_atlas"))
229 m_tsrc->buildMainAtlas(this);
231 infostream<<"Not building texture atlas."<<std::endl;
233 // Update node textures
234 m_nodedef->updateTextures(m_tsrc);
236 // Start threads after setting up content definitions
237 m_mesh_update_thread.Start();
243 Player *player = new LocalPlayer(this);
245 player->updateName(playername);
247 m_env.addPlayer(player);
249 // Initialize player in the inventory context
250 m_inventory_context.current_player = player;
257 //JMutexAutoLock conlock(m_con_mutex); //bulk comment-out
261 m_mesh_update_thread.setRun(false);
262 while(m_mesh_update_thread.IsRunning())
266 void Client::connect(Address address)
268 DSTACK(__FUNCTION_NAME);
269 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
270 m_con.SetTimeoutMs(0);
271 m_con.Connect(address);
274 bool Client::connectedAndInitialized()
276 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
278 if(m_con.Connected() == false)
281 if(m_server_ser_ver == SER_FMT_VER_INVALID)
287 void Client::step(float dtime)
289 DSTACK(__FUNCTION_NAME);
295 if(m_ignore_damage_timer > dtime)
296 m_ignore_damage_timer -= dtime;
298 m_ignore_damage_timer = 0.0;
300 //infostream<<"Client steps "<<dtime<<std::endl;
303 //TimeTaker timer("ReceiveAll()", m_device);
309 //TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device);
311 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
312 m_con.RunTimeouts(dtime);
319 float &counter = m_packetcounter_timer;
325 infostream<<"Client packetcounter (20s):"<<std::endl;
326 m_packetcounter.print(infostream);
327 m_packetcounter.clear();
331 // Get connection status
332 bool connected = connectedAndInitialized();
337 Delete unused sectors
339 NOTE: This jams the game for a while because deleting sectors
343 float &counter = m_delete_unused_sectors_timer;
351 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
353 core::list<v3s16> deleted_blocks;
355 float delete_unused_sectors_timeout =
356 g_settings->getFloat("client_delete_unused_sectors_timeout");
358 // Delete sector blocks
359 /*u32 num = m_env.getMap().unloadUnusedData
360 (delete_unused_sectors_timeout,
361 true, &deleted_blocks);*/
363 // Delete whole sectors
364 m_env.getMap().unloadUnusedData
365 (delete_unused_sectors_timeout,
368 if(deleted_blocks.size() > 0)
370 /*infostream<<"Client: Deleted blocks of "<<num
371 <<" unused sectors"<<std::endl;*/
372 /*infostream<<"Client: Deleted "<<num
373 <<" unused sectors"<<std::endl;*/
379 // Env is locked so con can be locked.
380 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
382 core::list<v3s16>::Iterator i = deleted_blocks.begin();
383 core::list<v3s16> sendlist;
386 if(sendlist.size() == 255 || i == deleted_blocks.end())
388 if(sendlist.size() == 0)
397 u32 replysize = 2+1+6*sendlist.size();
398 SharedBuffer<u8> reply(replysize);
399 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
400 reply[2] = sendlist.size();
402 for(core::list<v3s16>::Iterator
403 j = sendlist.begin();
404 j != sendlist.end(); j++)
406 writeV3S16(&reply[2+1+6*k], *j);
409 m_con.Send(PEER_ID_SERVER, 1, reply, true);
411 if(i == deleted_blocks.end())
417 sendlist.push_back(*i);
425 if(connected == false)
427 float &counter = m_connection_reinit_timer;
433 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
435 Player *myplayer = m_env.getLocalPlayer();
436 assert(myplayer != NULL);
438 // Send TOSERVER_INIT
439 // [0] u16 TOSERVER_INIT
440 // [2] u8 SER_FMT_VER_HIGHEST
441 // [3] u8[20] player_name
442 // [23] u8[28] password (new in some version)
443 // [51] u16 client network protocol version (new in some version)
444 SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2);
445 writeU16(&data[0], TOSERVER_INIT);
446 writeU8(&data[2], SER_FMT_VER_HIGHEST);
448 memset((char*)&data[3], 0, PLAYERNAME_SIZE);
449 snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
451 /*infostream<<"Client: sending initial password hash: \""<<m_password<<"\""
454 memset((char*)&data[23], 0, PASSWORD_SIZE);
455 snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
457 // This should be incremented in each version
458 writeU16(&data[51], PROTOCOL_VERSION);
460 // Send as unreliable
461 Send(0, data, false);
464 // Not connected, return
469 Do stuff if connected
473 Run Map's timers and unload unused data
475 const float map_timer_and_unload_dtime = 5.25;
476 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
478 ScopeProfiler sp(g_profiler, "Client: map timer and unload");
479 core::list<v3s16> deleted_blocks;
480 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
481 g_settings->getFloat("client_unload_unused_data_timeout"),
484 /*if(deleted_blocks.size() > 0)
485 infostream<<"Client: Unloaded "<<deleted_blocks.size()
486 <<" unused blocks"<<std::endl;*/
490 NOTE: This loop is intentionally iterated the way it is.
493 core::list<v3s16>::Iterator i = deleted_blocks.begin();
494 core::list<v3s16> sendlist;
497 if(sendlist.size() == 255 || i == deleted_blocks.end())
499 if(sendlist.size() == 0)
508 u32 replysize = 2+1+6*sendlist.size();
509 SharedBuffer<u8> reply(replysize);
510 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
511 reply[2] = sendlist.size();
513 for(core::list<v3s16>::Iterator
514 j = sendlist.begin();
515 j != sendlist.end(); j++)
517 writeV3S16(&reply[2+1+6*k], *j);
520 m_con.Send(PEER_ID_SERVER, 1, reply, true);
522 if(i == deleted_blocks.end())
528 sendlist.push_back(*i);
538 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
540 // Control local player (0ms)
541 LocalPlayer *player = m_env.getLocalPlayer();
542 assert(player != NULL);
543 player->applyControl(dtime);
545 //TimeTaker envtimer("env step", m_device);
554 ClientEnvEvent event = m_env.getClientEvent();
555 if(event.type == CEE_NONE)
559 else if(event.type == CEE_PLAYER_DAMAGE)
561 if(m_ignore_damage_timer <= 0)
563 u8 damage = event.player_damage.amount;
566 // Add to ClientEvent queue
568 event.type = CE_PLAYER_DAMAGE;
569 event.player_damage.amount = damage;
570 m_client_event_queue.push_back(event);
580 float &counter = m_avg_rtt_timer;
585 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
586 // connectedAndInitialized() is true, peer exists.
587 float avg_rtt = m_con.GetPeerAvgRTT(PEER_ID_SERVER);
588 infostream<<"Client: avg_rtt="<<avg_rtt<<std::endl;
593 Send player position to server
596 float &counter = m_playerpos_send_timer;
606 Replace updated meshes
609 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
611 //TimeTaker timer("** Processing mesh update result queue");
614 /*infostream<<"Mesh update result queue size is "
615 <<m_mesh_update_thread.m_queue_out.size()
618 while(m_mesh_update_thread.m_queue_out.size() > 0)
620 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
621 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
624 block->replaceMesh(r.mesh);
626 if(r.ack_block_to_server)
628 /*infostream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
629 <<","<<r.p.Z<<")"<<std::endl;*/
640 u32 replysize = 2+1+6;
641 SharedBuffer<u8> reply(replysize);
642 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
644 writeV3S16(&reply[3], r.p);
646 m_con.Send(PEER_ID_SERVER, 1, reply, true);
652 // Virtual methods from con::PeerHandler
653 void Client::peerAdded(con::Peer *peer)
655 infostream<<"Client::peerAdded(): peer->id="
656 <<peer->id<<std::endl;
658 void Client::deletingPeer(con::Peer *peer, bool timeout)
660 infostream<<"Client::deletingPeer(): "
661 "Server Peer is getting deleted "
662 <<"(timeout="<<timeout<<")"<<std::endl;
665 void Client::ReceiveAll()
667 DSTACK(__FUNCTION_NAME);
668 u32 start_ms = porting::getTimeMs();
671 // Limit time even if there would be huge amounts of data to
673 if(porting::getTimeMs() > start_ms + 100)
679 catch(con::NoIncomingDataException &e)
683 catch(con::InvalidIncomingDataException &e)
685 infostream<<"Client::ReceiveAll(): "
686 "InvalidIncomingDataException: what()="
687 <<e.what()<<std::endl;
692 void Client::Receive()
694 DSTACK(__FUNCTION_NAME);
695 SharedBuffer<u8> data;
699 //TimeTaker t1("con mutex and receive", m_device);
700 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
701 datasize = m_con.Receive(sender_peer_id, data);
703 //TimeTaker t1("ProcessData", m_device);
704 ProcessData(*data, datasize, sender_peer_id);
708 sender_peer_id given to this shall be quaranteed to be a valid peer
710 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
712 DSTACK(__FUNCTION_NAME);
714 // Ignore packets that don't even fit a command
717 m_packetcounter.add(60000);
721 ToClientCommand command = (ToClientCommand)readU16(&data[0]);
723 //infostream<<"Client: received command="<<command<<std::endl;
724 m_packetcounter.add((u16)command);
727 If this check is removed, be sure to change the queue
728 system to know the ids
730 if(sender_peer_id != PEER_ID_SERVER)
732 infostream<<"Client::ProcessData(): Discarding data not "
733 "coming from server: peer_id="<<sender_peer_id
738 u8 ser_version = m_server_ser_ver;
740 //infostream<<"Client received command="<<(int)command<<std::endl;
742 if(command == TOCLIENT_INIT)
747 u8 deployed = data[2];
749 infostream<<"Client: TOCLIENT_INIT received with "
750 "deployed="<<((int)deployed&0xff)<<std::endl;
752 if(deployed < SER_FMT_VER_LOWEST
753 || deployed > SER_FMT_VER_HIGHEST)
755 infostream<<"Client: TOCLIENT_INIT: Server sent "
756 <<"unsupported ser_fmt_ver"<<std::endl;
760 m_server_ser_ver = deployed;
762 // Get player position
763 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
764 if(datasize >= 2+1+6)
765 playerpos_s16 = readV3S16(&data[2+1]);
766 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
769 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
771 // Set player position
772 Player *player = m_env.getLocalPlayer();
773 assert(player != NULL);
774 player->setPosition(playerpos_f);
777 if(datasize >= 2+1+6+8)
780 m_map_seed = readU64(&data[2+1+6]);
781 infostream<<"Client: received map seed: "<<m_map_seed<<std::endl;
786 SharedBuffer<u8> reply(replysize);
787 writeU16(&reply[0], TOSERVER_INIT2);
789 m_con.Send(PEER_ID_SERVER, 1, reply, true);
794 if(command == TOCLIENT_ACCESS_DENIED)
796 // The server didn't like our password. Note, this needs
797 // to be processed even if the serialisation format has
798 // not been agreed yet, the same as TOCLIENT_INIT.
799 m_access_denied = true;
800 m_access_denied_reason = L"Unknown";
803 std::string datastring((char*)&data[2], datasize-2);
804 std::istringstream is(datastring, std::ios_base::binary);
805 m_access_denied_reason = deSerializeWideString(is);
810 if(ser_version == SER_FMT_VER_INVALID)
812 infostream<<"Client: Server serialization"
813 " format invalid or not initialized."
814 " Skipping incoming command="<<command<<std::endl;
818 // Just here to avoid putting the two if's together when
819 // making some copypasta
822 if(command == TOCLIENT_REMOVENODE)
827 p.X = readS16(&data[2]);
828 p.Y = readS16(&data[4]);
829 p.Z = readS16(&data[6]);
831 //TimeTaker t1("TOCLIENT_REMOVENODE");
833 // This will clear the cracking animation after digging
834 ((ClientMap&)m_env.getMap()).clearTempMod(p);
838 else if(command == TOCLIENT_ADDNODE)
840 if(datasize < 8 + MapNode::serializedLength(ser_version))
844 p.X = readS16(&data[2]);
845 p.Y = readS16(&data[4]);
846 p.Z = readS16(&data[6]);
848 //TimeTaker t1("TOCLIENT_ADDNODE");
851 n.deSerialize(&data[8], ser_version);
855 else if(command == TOCLIENT_BLOCKDATA)
857 // Ignore too small packet
862 p.X = readS16(&data[2]);
863 p.Y = readS16(&data[4]);
864 p.Z = readS16(&data[6]);
866 /*infostream<<"Client: Thread: BLOCKDATA for ("
867 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
868 /*infostream<<"Client: Thread: BLOCKDATA for ("
869 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
871 std::string datastring((char*)&data[8], datasize-8);
872 std::istringstream istr(datastring, std::ios_base::binary);
878 sector = m_env.getMap().emergeSector(p2d);
880 assert(sector->getPos() == p2d);
882 //TimeTaker timer("MapBlock deSerialize");
885 block = sector->getBlockNoCreateNoEx(p.Y);
889 Update an existing block
891 //infostream<<"Updating"<<std::endl;
892 block->deSerialize(istr, ser_version);
899 //infostream<<"Creating new"<<std::endl;
900 block = new MapBlock(&m_env.getMap(), p, this);
901 block->deSerialize(istr, ser_version);
902 sector->insertBlock(block);
906 mod.type = NODEMOD_CHANGECONTENT;
907 mod.param = CONTENT_MESE;
908 block->setTempMod(v3s16(8,10,8), mod);
909 block->setTempMod(v3s16(8,9,8), mod);
910 block->setTempMod(v3s16(8,8,8), mod);
911 block->setTempMod(v3s16(8,7,8), mod);
912 block->setTempMod(v3s16(8,6,8), mod);*/
926 u32 replysize = 2+1+6;
927 SharedBuffer<u8> reply(replysize);
928 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
930 writeV3S16(&reply[3], p);
932 m_con.Send(PEER_ID_SERVER, 1, reply, true);
936 Update Mesh of this block and blocks at x-, y- and z-.
937 Environment should not be locked as it interlocks with the
938 main thread, from which is will want to retrieve textures.
941 //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
943 Add it to mesh update queue and set it to be acknowledged after update.
945 //infostream<<"Adding mesh update task for received block"<<std::endl;
946 addUpdateMeshTaskWithEdge(p, true);
948 else if(command == TOCLIENT_PLAYERPOS)
950 infostream<<"Received deprecated TOCLIENT_PLAYERPOS"
954 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
955 our_peer_id = m_con.GetPeerID();
957 // Cancel if we don't have a peer id
958 if(our_peer_id == PEER_ID_INEXISTENT){
959 infostream<<"TOCLIENT_PLAYERPOS cancelled: "
966 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
968 u32 player_size = 2+12+12+4+4;
970 u32 player_count = (datasize-2) / player_size;
972 for(u32 i=0; i<player_count; i++)
974 u16 peer_id = readU16(&data[start]);
976 Player *player = m_env.getPlayer(peer_id);
978 // Skip if player doesn't exist
981 start += player_size;
985 // Skip if player is local player
986 if(player->isLocal())
988 start += player_size;
992 v3s32 ps = readV3S32(&data[start+2]);
993 v3s32 ss = readV3S32(&data[start+2+12]);
994 s32 pitch_i = readS32(&data[start+2+12+12]);
995 s32 yaw_i = readS32(&data[start+2+12+12+4]);
996 /*infostream<<"Client: got "
997 <<"pitch_i="<<pitch_i
998 <<" yaw_i="<<yaw_i<<std::endl;*/
999 f32 pitch = (f32)pitch_i / 100.0;
1000 f32 yaw = (f32)yaw_i / 100.0;
1001 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1002 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1003 player->setPosition(position);
1004 player->setSpeed(speed);
1005 player->setPitch(pitch);
1006 player->setYaw(yaw);
1008 /*infostream<<"Client: player "<<peer_id
1010 <<" yaw="<<yaw<<std::endl;*/
1012 start += player_size;
1016 else if(command == TOCLIENT_PLAYERINFO)
1020 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1021 our_peer_id = m_con.GetPeerID();
1023 // Cancel if we don't have a peer id
1024 if(our_peer_id == PEER_ID_INEXISTENT){
1025 infostream<<"TOCLIENT_PLAYERINFO cancelled: "
1026 "we have no peer id"
1031 //infostream<<"Client: Server reports players:"<<std::endl;
1034 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1036 u32 item_size = 2+PLAYERNAME_SIZE;
1037 u32 player_count = (datasize-2) / item_size;
1040 core::list<u16> players_alive;
1041 for(u32 i=0; i<player_count; i++)
1043 // Make sure the name ends in '\0'
1044 data[start+2+20-1] = 0;
1046 u16 peer_id = readU16(&data[start]);
1048 players_alive.push_back(peer_id);
1050 /*infostream<<"peer_id="<<peer_id
1051 <<" name="<<((char*)&data[start+2])<<std::endl;*/
1053 // Don't update the info of the local player
1054 if(peer_id == our_peer_id)
1060 Player *player = m_env.getPlayer(peer_id);
1062 // Create a player if it doesn't exist
1065 player = new RemotePlayer(this,
1066 m_device->getSceneManager()->getRootSceneNode(),
1069 player->peer_id = peer_id;
1070 m_env.addPlayer(player);
1071 infostream<<"Client: Adding new player "
1072 <<peer_id<<std::endl;
1075 player->updateName((char*)&data[start+2]);
1081 Remove those players from the environment that
1082 weren't listed by the server.
1084 //infostream<<"Removing dead players"<<std::endl;
1085 core::list<Player*> players = m_env.getPlayers();
1086 core::list<Player*>::Iterator ip;
1087 for(ip=players.begin(); ip!=players.end(); ip++)
1089 // Ingore local player
1090 if((*ip)->isLocal())
1093 // Warn about a special case
1094 if((*ip)->peer_id == 0)
1096 infostream<<"Client: Removing "
1097 "dead player with id=0"<<std::endl;
1100 bool is_alive = false;
1101 core::list<u16>::Iterator i;
1102 for(i=players_alive.begin(); i!=players_alive.end(); i++)
1104 if((*ip)->peer_id == *i)
1110 /*infostream<<"peer_id="<<((*ip)->peer_id)
1111 <<" is_alive="<<is_alive<<std::endl;*/
1114 infostream<<"Removing dead player "<<(*ip)->peer_id
1116 m_env.removePlayer((*ip)->peer_id);
1120 else if(command == TOCLIENT_SECTORMETA)
1122 infostream<<"Client received DEPRECATED TOCLIENT_SECTORMETA"<<std::endl;
1127 [3...] v2s16 pos + sector metadata
1132 //infostream<<"Client received TOCLIENT_SECTORMETA"<<std::endl;
1135 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1137 std::string datastring((char*)&data[2], datasize-2);
1138 std::istringstream is(datastring, std::ios_base::binary);
1142 is.read((char*)buf, 1);
1143 u16 sector_count = readU8(buf);
1145 //infostream<<"sector_count="<<sector_count<<std::endl;
1147 for(u16 i=0; i<sector_count; i++)
1150 is.read((char*)buf, 4);
1151 v2s16 pos = readV2S16(buf);
1152 /*infostream<<"Client: deserializing sector at "
1153 <<"("<<pos.X<<","<<pos.Y<<")"<<std::endl;*/
1155 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
1156 ((ClientMap&)m_env.getMap()).deSerializeSector(pos, is);
1161 else if(command == TOCLIENT_INVENTORY)
1166 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
1169 //TimeTaker t2("mutex locking", m_device);
1170 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1173 //TimeTaker t3("istringstream init", m_device);
1174 std::string datastring((char*)&data[2], datasize-2);
1175 std::istringstream is(datastring, std::ios_base::binary);
1178 //m_env.printPlayers(infostream);
1180 //TimeTaker t4("player get", m_device);
1181 Player *player = m_env.getLocalPlayer();
1182 assert(player != NULL);
1185 //TimeTaker t1("inventory.deSerialize()", m_device);
1186 player->inventory.deSerialize(is, this);
1189 m_inventory_updated = true;
1191 //infostream<<"Client got player inventory:"<<std::endl;
1192 //player->inventory.print(infostream);
1196 else if(command == TOCLIENT_OBJECTDATA)
1198 // Strip command word and create a stringstream
1199 std::string datastring((char*)&data[2], datasize-2);
1200 std::istringstream is(datastring, std::ios_base::binary);
1208 is.read((char*)buf, 2);
1209 u16 playercount = readU16(buf);
1211 for(u16 i=0; i<playercount; i++)
1213 is.read((char*)buf, 2);
1214 u16 peer_id = readU16(buf);
1215 is.read((char*)buf, 12);
1216 v3s32 p_i = readV3S32(buf);
1217 is.read((char*)buf, 12);
1218 v3s32 s_i = readV3S32(buf);
1219 is.read((char*)buf, 4);
1220 s32 pitch_i = readS32(buf);
1221 is.read((char*)buf, 4);
1222 s32 yaw_i = readS32(buf);
1224 Player *player = m_env.getPlayer(peer_id);
1226 // Skip if player doesn't exist
1232 // Skip if player is local player
1233 if(player->isLocal())
1238 f32 pitch = (f32)pitch_i / 100.0;
1239 f32 yaw = (f32)yaw_i / 100.0;
1240 v3f position((f32)p_i.X/100., (f32)p_i.Y/100., (f32)p_i.Z/100.);
1241 v3f speed((f32)s_i.X/100., (f32)s_i.Y/100., (f32)s_i.Z/100.);
1243 player->setPosition(position);
1244 player->setSpeed(speed);
1245 player->setPitch(pitch);
1246 player->setYaw(yaw);
1251 NOTE: Deprecated stuff
1254 // Read active block count
1255 u16 blockcount = readU16(is);
1256 if(blockcount != 0){
1257 infostream<<"TOCLIENT_OBJECTDATA: blockcount != 0 "
1258 "not supported"<<std::endl;
1262 else if(command == TOCLIENT_TIME_OF_DAY)
1267 u16 time_of_day = readU16(&data[2]);
1268 time_of_day = time_of_day % 24000;
1269 //infostream<<"Client: time_of_day="<<time_of_day<<std::endl;
1277 m_env.setTimeOfDay(time_of_day);
1279 u32 dr = m_env.getDayNightRatio();
1281 infostream<<"Client: time_of_day="<<time_of_day
1287 else if(command == TOCLIENT_CHAT_MESSAGE)
1295 std::string datastring((char*)&data[2], datasize-2);
1296 std::istringstream is(datastring, std::ios_base::binary);
1299 is.read((char*)buf, 2);
1300 u16 len = readU16(buf);
1302 std::wstring message;
1303 for(u16 i=0; i<len; i++)
1305 is.read((char*)buf, 2);
1306 message += (wchar_t)readU16(buf);
1309 /*infostream<<"Client received chat message: "
1310 <<wide_to_narrow(message)<<std::endl;*/
1312 m_chat_queue.push_back(message);
1314 else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1316 //if(g_settings->getBool("enable_experimental"))
1320 u16 count of removed objects
1321 for all removed objects {
1324 u16 count of added objects
1325 for all added objects {
1328 u32 initialization data length
1329 string initialization data
1334 // Get all data except the command number
1335 std::string datastring((char*)&data[2], datasize-2);
1336 // Throw them in an istringstream
1337 std::istringstream is(datastring, std::ios_base::binary);
1341 // Read removed objects
1343 u16 removed_count = readU16((u8*)buf);
1344 for(u16 i=0; i<removed_count; i++)
1347 u16 id = readU16((u8*)buf);
1350 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1351 m_env.removeActiveObject(id);
1355 // Read added objects
1357 u16 added_count = readU16((u8*)buf);
1358 for(u16 i=0; i<added_count; i++)
1361 u16 id = readU16((u8*)buf);
1363 u8 type = readU8((u8*)buf);
1364 std::string data = deSerializeLongString(is);
1367 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1368 m_env.addActiveObject(id, type, data);
1373 else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1375 //if(g_settings->getBool("enable_experimental"))
1387 // Get all data except the command number
1388 std::string datastring((char*)&data[2], datasize-2);
1389 // Throw them in an istringstream
1390 std::istringstream is(datastring, std::ios_base::binary);
1392 while(is.eof() == false)
1396 u16 id = readU16((u8*)buf);
1400 u16 message_size = readU16((u8*)buf);
1401 std::string message;
1402 message.reserve(message_size);
1403 for(u16 i=0; i<message_size; i++)
1406 message.append(buf, 1);
1408 // Pass on to the environment
1410 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1411 m_env.processActiveObjectMessage(id, message);
1416 else if(command == TOCLIENT_HP)
1418 std::string datastring((char*)&data[2], datasize-2);
1419 std::istringstream is(datastring, std::ios_base::binary);
1420 Player *player = m_env.getLocalPlayer();
1421 assert(player != NULL);
1425 else if(command == TOCLIENT_MOVE_PLAYER)
1427 std::string datastring((char*)&data[2], datasize-2);
1428 std::istringstream is(datastring, std::ios_base::binary);
1429 Player *player = m_env.getLocalPlayer();
1430 assert(player != NULL);
1431 v3f pos = readV3F1000(is);
1432 f32 pitch = readF1000(is);
1433 f32 yaw = readF1000(is);
1434 player->setPosition(pos);
1435 /*player->setPitch(pitch);
1436 player->setYaw(yaw);*/
1438 infostream<<"Client got TOCLIENT_MOVE_PLAYER"
1439 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1445 Add to ClientEvent queue.
1446 This has to be sent to the main program because otherwise
1447 it would just force the pitch and yaw values to whatever
1448 the camera points to.
1451 event.type = CE_PLAYER_FORCE_MOVE;
1452 event.player_force_move.pitch = pitch;
1453 event.player_force_move.yaw = yaw;
1454 m_client_event_queue.push_back(event);
1456 // Ignore damage for a few seconds, so that the player doesn't
1457 // get damage from falling on ground
1458 m_ignore_damage_timer = 3.0;
1460 else if(command == TOCLIENT_PLAYERITEM)
1462 std::string datastring((char*)&data[2], datasize-2);
1463 std::istringstream is(datastring, std::ios_base::binary);
1465 u16 count = readU16(is);
1467 for (u16 i = 0; i < count; ++i) {
1468 u16 peer_id = readU16(is);
1469 Player *player = m_env.getPlayer(peer_id);
1473 infostream<<"Client: ignoring player item "
1474 << deSerializeString(is)
1475 << " for non-existing peer id " << peer_id
1478 } else if (player->isLocal()) {
1479 infostream<<"Client: ignoring player item "
1480 << deSerializeString(is)
1481 << " for local player" << std::endl;
1484 InventoryList *inv = player->inventory.getList("main");
1485 std::string itemstring(deSerializeString(is));
1486 if (itemstring.empty()) {
1489 <<"Client: empty player item for peer "
1490 << peer_id << std::endl;
1492 std::istringstream iss(itemstring);
1493 delete inv->changeItem(0,
1494 InventoryItem::deSerialize(iss, this));
1495 infostream<<"Client: player item for peer " << peer_id << ": ";
1496 player->getWieldItem()->serialize(infostream);
1497 infostream<<std::endl;
1502 else if(command == TOCLIENT_DEATHSCREEN)
1504 std::string datastring((char*)&data[2], datasize-2);
1505 std::istringstream is(datastring, std::ios_base::binary);
1507 bool set_camera_point_target = readU8(is);
1508 v3f camera_point_target = readV3F1000(is);
1511 event.type = CE_DEATHSCREEN;
1512 event.deathscreen.set_camera_point_target = set_camera_point_target;
1513 event.deathscreen.camera_point_target_x = camera_point_target.X;
1514 event.deathscreen.camera_point_target_y = camera_point_target.Y;
1515 event.deathscreen.camera_point_target_z = camera_point_target.Z;
1516 m_client_event_queue.push_back(event);
1518 else if(command == TOCLIENT_TEXTURES)
1520 io::IFileSystem *irrfs = m_device->getFileSystem();
1521 video::IVideoDriver *vdrv = m_device->getVideoDriver();
1523 std::string datastring((char*)&data[2], datasize-2);
1524 std::istringstream is(datastring, std::ios_base::binary);
1526 // Stop threads while updating content definitions
1527 m_mesh_update_thread.stop();
1531 u16 total number of texture bunches
1532 u16 index of this bunch
1533 u32 number of textures in this bunch
1541 int num_bunches = readU16(is);
1542 int bunch_i = readU16(is);
1543 m_texture_receive_progress = (float)bunch_i / (float)(num_bunches - 1);
1544 if(bunch_i == num_bunches - 1)
1545 m_textures_received = true;
1546 int num_textures = readU32(is);
1547 infostream<<"Client: Received textures: bunch "<<bunch_i<<"/"
1548 <<num_bunches<<" textures="<<num_textures
1549 <<" size="<<datasize<<std::endl;
1550 for(int i=0; i<num_textures; i++){
1551 std::string name = deSerializeString(is);
1552 std::string data = deSerializeLongString(is);
1553 // Silly irrlicht's const-incorrectness
1554 Buffer<char> data_rw(data.c_str(), data.size());
1555 // Create an irrlicht memory file
1556 io::IReadFile *rfile = irrfs->createMemoryReadFile(
1557 *data_rw, data.size(), "_tempreadfile");
1560 video::IImage *img = vdrv->createImageFromFile(rfile);
1562 errorstream<<"Client: Cannot create image from data of "
1563 <<"received texture \""<<name<<"\""<<std::endl;
1567 m_tsrc->insertSourceImage(name, img);
1572 if(m_nodedef_received && m_textures_received){
1573 // Rebuild inherited images and recreate textures
1574 m_tsrc->rebuildImagesAndTextures();
1576 // Update texture atlas
1577 if(g_settings->getBool("enable_texture_atlas"))
1578 m_tsrc->buildMainAtlas(this);
1580 // Update node textures
1581 m_nodedef->updateTextures(m_tsrc);
1585 m_mesh_update_thread.setRun(true);
1586 m_mesh_update_thread.Start();
1589 event.type = CE_TEXTURES_UPDATED;
1590 m_client_event_queue.push_back(event);
1592 else if(command == TOCLIENT_TOOLDEF)
1594 infostream<<"Client: Received tool definitions: packet size: "
1595 <<datasize<<std::endl;
1597 std::string datastring((char*)&data[2], datasize-2);
1598 std::istringstream is(datastring, std::ios_base::binary);
1600 m_tooldef_received = true;
1602 // Stop threads while updating content definitions
1603 m_mesh_update_thread.stop();
1605 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1606 m_tooldef->deSerialize(tmp_is);
1609 m_mesh_update_thread.setRun(true);
1610 m_mesh_update_thread.Start();
1612 else if(command == TOCLIENT_NODEDEF)
1614 infostream<<"Client: Received node definitions: packet size: "
1615 <<datasize<<std::endl;
1617 std::string datastring((char*)&data[2], datasize-2);
1618 std::istringstream is(datastring, std::ios_base::binary);
1620 m_nodedef_received = true;
1622 // Stop threads while updating content definitions
1623 m_mesh_update_thread.stop();
1625 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1626 m_nodedef->deSerialize(tmp_is, this);
1628 if(m_textures_received){
1629 // Update texture atlas
1630 if(g_settings->getBool("enable_texture_atlas"))
1631 m_tsrc->buildMainAtlas(this);
1633 // Update node textures
1634 m_nodedef->updateTextures(m_tsrc);
1638 m_mesh_update_thread.setRun(true);
1639 m_mesh_update_thread.Start();
1643 infostream<<"Client: Ignoring unknown command "
1644 <<command<<std::endl;
1648 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1650 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1651 m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1654 void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
1655 v3s16 nodepos_oversurface, u16 item)
1657 if(connectedAndInitialized() == false){
1658 infostream<<"Client::groundAction() "
1659 "cancelled (not connected)"
1668 [3] v3s16 nodepos_undersurface
1669 [9] v3s16 nodepos_abovesurface
1674 2: stop digging (all parameters ignored)
1675 3: digging completed
1677 u8 datasize = 2 + 1 + 6 + 6 + 2;
1678 SharedBuffer<u8> data(datasize);
1679 writeU16(&data[0], TOSERVER_GROUND_ACTION);
1680 writeU8(&data[2], action);
1681 writeV3S16(&data[3], nodepos_undersurface);
1682 writeV3S16(&data[9], nodepos_oversurface);
1683 writeU16(&data[15], item);
1684 Send(0, data, true);
1687 void Client::clickActiveObject(u8 button, u16 id, u16 item_i)
1689 if(connectedAndInitialized() == false){
1690 infostream<<"Client::clickActiveObject() "
1691 "cancelled (not connected)"
1696 Player *player = m_env.getLocalPlayer();
1700 ClientActiveObject *obj = m_env.getActiveObject(id);
1703 ToolItem *titem = NULL;
1704 std::string toolname = "";
1706 InventoryList *mlist = player->inventory.getList("main");
1709 InventoryItem *item = mlist->getItem(item_i);
1710 if(item && (std::string)item->getName() == "ToolItem")
1712 titem = (ToolItem*)item;
1713 toolname = titem->getToolName();
1717 v3f playerpos = player->getPosition();
1718 v3f objpos = obj->getPosition();
1719 v3f dir = (objpos - playerpos).normalize();
1721 bool disable_send = obj->directReportPunch(toolname, dir);
1731 [2] u8 button (0=left, 1=right)
1735 u8 datasize = 2 + 1 + 6 + 2 + 2;
1736 SharedBuffer<u8> data(datasize);
1737 writeU16(&data[0], TOSERVER_CLICK_ACTIVEOBJECT);
1738 writeU8(&data[2], button);
1739 writeU16(&data[3], id);
1740 writeU16(&data[5], item_i);
1741 Send(0, data, true);
1744 void Client::sendSignNodeText(v3s16 p, std::string text)
1752 std::ostringstream os(std::ios_base::binary);
1756 writeU16(buf, TOSERVER_SIGNNODETEXT);
1757 os.write((char*)buf, 2);
1761 os.write((char*)buf, 6);
1763 u16 textlen = text.size();
1764 // Write text length
1765 writeS16(buf, textlen);
1766 os.write((char*)buf, 2);
1769 os.write((char*)text.c_str(), textlen);
1772 std::string s = os.str();
1773 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1775 Send(0, data, true);
1778 void Client::sendInventoryAction(InventoryAction *a)
1780 std::ostringstream os(std::ios_base::binary);
1784 writeU16(buf, TOSERVER_INVENTORY_ACTION);
1785 os.write((char*)buf, 2);
1790 std::string s = os.str();
1791 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1793 Send(0, data, true);
1796 void Client::sendChatMessage(const std::wstring &message)
1798 std::ostringstream os(std::ios_base::binary);
1802 writeU16(buf, TOSERVER_CHAT_MESSAGE);
1803 os.write((char*)buf, 2);
1806 writeU16(buf, message.size());
1807 os.write((char*)buf, 2);
1810 for(u32 i=0; i<message.size(); i++)
1814 os.write((char*)buf, 2);
1818 std::string s = os.str();
1819 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1821 Send(0, data, true);
1824 void Client::sendChangePassword(const std::wstring oldpassword,
1825 const std::wstring newpassword)
1827 Player *player = m_env.getLocalPlayer();
1831 std::string playername = player->getName();
1832 std::string oldpwd = translatePassword(playername, oldpassword);
1833 std::string newpwd = translatePassword(playername, newpassword);
1835 std::ostringstream os(std::ios_base::binary);
1836 u8 buf[2+PASSWORD_SIZE*2];
1838 [0] u16 TOSERVER_PASSWORD
1839 [2] u8[28] old password
1840 [30] u8[28] new password
1843 writeU16(buf, TOSERVER_PASSWORD);
1844 for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1846 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1847 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1849 buf[2+PASSWORD_SIZE-1] = 0;
1850 buf[30+PASSWORD_SIZE-1] = 0;
1851 os.write((char*)buf, 2+PASSWORD_SIZE*2);
1854 std::string s = os.str();
1855 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1857 Send(0, data, true);
1861 void Client::sendDamage(u8 damage)
1863 DSTACK(__FUNCTION_NAME);
1864 std::ostringstream os(std::ios_base::binary);
1866 writeU16(os, TOSERVER_DAMAGE);
1867 writeU8(os, damage);
1870 std::string s = os.str();
1871 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1873 Send(0, data, true);
1876 void Client::sendRespawn()
1878 DSTACK(__FUNCTION_NAME);
1879 std::ostringstream os(std::ios_base::binary);
1881 writeU16(os, TOSERVER_RESPAWN);
1884 std::string s = os.str();
1885 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1887 Send(0, data, true);
1890 void Client::sendPlayerPos()
1892 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1894 Player *myplayer = m_env.getLocalPlayer();
1895 if(myplayer == NULL)
1900 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1901 our_peer_id = m_con.GetPeerID();
1904 // Set peer id if not set already
1905 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1906 myplayer->peer_id = our_peer_id;
1907 // Check that an existing peer_id is the same as the connection's
1908 assert(myplayer->peer_id == our_peer_id);
1910 v3f pf = myplayer->getPosition();
1911 v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1912 v3f sf = myplayer->getSpeed();
1913 v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1914 s32 pitch = myplayer->getPitch() * 100;
1915 s32 yaw = myplayer->getYaw() * 100;
1920 [2] v3s32 position*100
1921 [2+12] v3s32 speed*100
1922 [2+12+12] s32 pitch*100
1923 [2+12+12+4] s32 yaw*100
1926 SharedBuffer<u8> data(2+12+12+4+4);
1927 writeU16(&data[0], TOSERVER_PLAYERPOS);
1928 writeV3S32(&data[2], position);
1929 writeV3S32(&data[2+12], speed);
1930 writeS32(&data[2+12+12], pitch);
1931 writeS32(&data[2+12+12+4], yaw);
1933 // Send as unreliable
1934 Send(0, data, false);
1937 void Client::sendPlayerItem(u16 item)
1939 Player *myplayer = m_env.getLocalPlayer();
1940 if(myplayer == NULL)
1943 u16 our_peer_id = m_con.GetPeerID();
1945 // Set peer id if not set already
1946 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1947 myplayer->peer_id = our_peer_id;
1948 // Check that an existing peer_id is the same as the connection's
1949 assert(myplayer->peer_id == our_peer_id);
1951 SharedBuffer<u8> data(2+2);
1952 writeU16(&data[0], TOSERVER_PLAYERITEM);
1953 writeU16(&data[2], item);
1956 Send(0, data, true);
1959 void Client::removeNode(v3s16 p)
1961 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1963 core::map<v3s16, MapBlock*> modified_blocks;
1967 //TimeTaker t("removeNodeAndUpdate", m_device);
1968 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1970 catch(InvalidPositionException &e)
1974 for(core::map<v3s16, MapBlock * >::Iterator
1975 i = modified_blocks.getIterator();
1976 i.atEnd() == false; i++)
1978 v3s16 p = i.getNode()->getKey();
1979 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1980 addUpdateMeshTaskWithEdge(p);
1984 void Client::addNode(v3s16 p, MapNode n)
1986 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1988 TimeTaker timer1("Client::addNode()");
1990 core::map<v3s16, MapBlock*> modified_blocks;
1994 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1995 std::string st = std::string("");
1996 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st);
1998 catch(InvalidPositionException &e)
2001 //TimeTaker timer2("Client::addNode(): updateMeshes");
2003 for(core::map<v3s16, MapBlock * >::Iterator
2004 i = modified_blocks.getIterator();
2005 i.atEnd() == false; i++)
2007 v3s16 p = i.getNode()->getKey();
2008 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
2009 addUpdateMeshTaskWithEdge(p);
2013 void Client::updateCamera(v3f pos, v3f dir, f32 fov)
2015 m_env.getClientMap().updateCamera(pos, dir, fov);
2018 void Client::renderPostFx()
2020 m_env.getClientMap().renderPostFx();
2023 MapNode Client::getNode(v3s16 p)
2025 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2026 return m_env.getMap().getNode(p);
2029 NodeMetadata* Client::getNodeMetadata(v3s16 p)
2031 return m_env.getMap().getNodeMetadata(p);
2034 LocalPlayer* Client::getLocalPlayer()
2036 return m_env.getLocalPlayer();
2039 void Client::setPlayerControl(PlayerControl &control)
2041 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2042 LocalPlayer *player = m_env.getLocalPlayer();
2043 assert(player != NULL);
2044 player->control = control;
2047 void Client::selectPlayerItem(u16 item)
2049 LocalPlayer *player = m_env.getLocalPlayer();
2050 assert(player != NULL);
2052 player->wieldItem(item);
2054 sendPlayerItem(item);
2057 // Returns true if the inventory of the local player has been
2058 // updated from the server. If it is true, it is set to false.
2059 bool Client::getLocalInventoryUpdated()
2061 // m_inventory_updated is behind envlock
2062 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2063 bool updated = m_inventory_updated;
2064 m_inventory_updated = false;
2068 // Copies the inventory of the local player to parameter
2069 void Client::getLocalInventory(Inventory &dst)
2071 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2072 Player *player = m_env.getLocalPlayer();
2073 assert(player != NULL);
2074 dst = player->inventory;
2077 InventoryContext *Client::getInventoryContext()
2079 return &m_inventory_context;
2082 Inventory* Client::getInventory(InventoryContext *c, std::string id)
2084 if(id == "current_player")
2086 assert(c->current_player);
2087 return &(c->current_player->inventory);
2091 std::string id0 = fn.next(":");
2093 if(id0 == "nodemeta")
2096 p.X = stoi(fn.next(","));
2097 p.Y = stoi(fn.next(","));
2098 p.Z = stoi(fn.next(","));
2099 NodeMetadata* meta = getNodeMetadata(p);
2101 return meta->getInventory();
2102 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
2103 <<"no metadata found"<<std::endl;
2107 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
2110 void Client::inventoryAction(InventoryAction *a)
2112 sendInventoryAction(a);
2115 ClientActiveObject * Client::getSelectedActiveObject(
2117 v3f from_pos_f_on_map,
2118 core::line3d<f32> shootline_on_map
2121 core::array<DistanceSortedActiveObject> objects;
2123 m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2125 //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2128 // After this, the closest object is the first in the array.
2131 for(u32 i=0; i<objects.size(); i++)
2133 ClientActiveObject *obj = objects[i].obj;
2135 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2136 if(selection_box == NULL)
2139 v3f pos = obj->getPosition();
2141 core::aabbox3d<f32> offsetted_box(
2142 selection_box->MinEdge + pos,
2143 selection_box->MaxEdge + pos
2146 if(offsetted_box.intersectsWithLine(shootline_on_map))
2148 //infostream<<"Returning selected object"<<std::endl;
2153 //infostream<<"No object selected; returning NULL."<<std::endl;
2157 void Client::printDebugInfo(std::ostream &os)
2159 //JMutexAutoLock lock1(m_fetchblock_mutex);
2160 /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2162 os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2163 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2164 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2168 u32 Client::getDayNightRatio()
2170 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2171 return m_env.getDayNightRatio();
2176 Player *player = m_env.getLocalPlayer();
2177 assert(player != NULL);
2181 void Client::setTempMod(v3s16 p, NodeMod mod)
2183 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2184 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2186 core::map<v3s16, MapBlock*> affected_blocks;
2187 ((ClientMap&)m_env.getMap()).setTempMod(p, mod,
2190 for(core::map<v3s16, MapBlock*>::Iterator
2191 i = affected_blocks.getIterator();
2192 i.atEnd() == false; i++)
2194 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2198 void Client::clearTempMod(v3s16 p)
2200 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2201 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2203 core::map<v3s16, MapBlock*> affected_blocks;
2204 ((ClientMap&)m_env.getMap()).clearTempMod(p,
2207 for(core::map<v3s16, MapBlock*>::Iterator
2208 i = affected_blocks.getIterator();
2209 i.atEnd() == false; i++)
2211 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2215 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
2217 /*infostream<<"Client::addUpdateMeshTask(): "
2218 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2221 MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2226 Create a task to update the mesh of the block
2229 MeshMakeData *data = new MeshMakeData;
2232 //TimeTaker timer("data fill");
2234 // Debug: 1-6ms, avg=2ms
2235 data->fill(getDayNightRatio(), b);
2239 //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2241 // Add task to queue
2242 m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server);
2244 /*infostream<<"Mesh update input queue size is "
2245 <<m_mesh_update_thread.m_queue_in.size()
2249 // Temporary test: make mesh directly in here
2251 //TimeTaker timer("make mesh");
2253 scene::SMesh *mesh_new = NULL;
2254 mesh_new = makeMapBlockMesh(data);
2255 b->replaceMesh(mesh_new);
2261 Mark mesh as non-expired at this point so that it can already
2262 be marked as expired again if the data changes
2264 b->setMeshExpired(false);
2267 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
2271 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2272 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2277 v3s16 p = blockpos + v3s16(0,0,0);
2278 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2279 addUpdateMeshTask(p, ack_to_server);
2281 catch(InvalidPositionException &e){}
2284 v3s16 p = blockpos + v3s16(-1,0,0);
2285 addUpdateMeshTask(p);
2287 catch(InvalidPositionException &e){}
2289 v3s16 p = blockpos + v3s16(0,-1,0);
2290 addUpdateMeshTask(p);
2292 catch(InvalidPositionException &e){}
2294 v3s16 p = blockpos + v3s16(0,0,-1);
2295 addUpdateMeshTask(p);
2297 catch(InvalidPositionException &e){}
2300 ClientEvent Client::getClientEvent()
2302 if(m_client_event_queue.size() == 0)
2305 event.type = CE_NONE;
2308 return m_client_event_queue.pop_front();
2311 float Client::getRTT(void)
2314 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2315 } catch(con::PeerNotFoundException &e){
2320 // IGameDef interface
2322 IToolDefManager* Client::getToolDefManager()
2326 INodeDefManager* Client::getNodeDefManager()
2330 ITextureSource* Client::getTextureSource()
2334 u16 Client::allocateUnknownNodeId(const std::string &name)
2336 errorstream<<"Client::allocateUnknownNodeId(): "
2337 <<"Client cannot allocate node IDs"<<std::endl;
2339 return CONTENT_IGNORE;