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 "craftitemdef.h"
38 #include <IFileSystem.h>
44 QueuedMeshUpdate::QueuedMeshUpdate():
47 ack_block_to_server(false)
51 QueuedMeshUpdate::~QueuedMeshUpdate()
61 MeshUpdateQueue::MeshUpdateQueue()
66 MeshUpdateQueue::~MeshUpdateQueue()
68 JMutexAutoLock lock(m_mutex);
70 core::list<QueuedMeshUpdate*>::Iterator i;
71 for(i=m_queue.begin(); i!=m_queue.end(); i++)
73 QueuedMeshUpdate *q = *i;
79 peer_id=0 adds with nobody to send to
81 void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server)
83 DSTACK(__FUNCTION_NAME);
87 JMutexAutoLock lock(m_mutex);
90 Find if block is already in queue.
91 If it is, update the data and quit.
93 core::list<QueuedMeshUpdate*>::Iterator i;
94 for(i=m_queue.begin(); i!=m_queue.end(); i++)
96 QueuedMeshUpdate *q = *i;
102 if(ack_block_to_server)
103 q->ack_block_to_server = true;
111 QueuedMeshUpdate *q = new QueuedMeshUpdate;
114 q->ack_block_to_server = ack_block_to_server;
115 m_queue.push_back(q);
118 // Returned pointer must be deleted
119 // Returns NULL if queue is empty
120 QueuedMeshUpdate * MeshUpdateQueue::pop()
122 JMutexAutoLock lock(m_mutex);
124 core::list<QueuedMeshUpdate*>::Iterator i = m_queue.begin();
125 if(i == m_queue.end())
127 QueuedMeshUpdate *q = *i;
136 void * MeshUpdateThread::Thread()
140 log_register_thread("MeshUpdateThread");
142 DSTACK(__FUNCTION_NAME);
144 BEGIN_DEBUG_EXCEPTION_HANDLER
148 /*// Wait for output queue to flush.
149 // Allow 2 in queue, this makes less frametime jitter.
150 // Umm actually, there is no much difference
151 if(m_queue_out.size() >= 2)
157 QueuedMeshUpdate *q = m_queue_in.pop();
164 ScopeProfiler sp(g_profiler, "Client: Mesh making");
166 scene::SMesh *mesh_new = NULL;
167 mesh_new = makeMapBlockMesh(q->data, m_gamedef);
172 r.ack_block_to_server = q->ack_block_to_server;
174 /*infostream<<"MeshUpdateThread: Processed "
175 <<"("<<q->p.X<<","<<q->p.Y<<","<<q->p.Z<<")"
178 m_queue_out.push_back(r);
183 END_DEBUG_EXCEPTION_HANDLER(errorstream)
189 IrrlichtDevice *device,
190 const char *playername,
191 std::string password,
192 MapDrawControl &control,
193 IWritableTextureSource *tsrc,
194 IWritableToolDefManager *tooldef,
195 IWritableNodeDefManager *nodedef,
196 IWritableCraftItemDefManager *craftitemdef
201 m_craftitemdef(craftitemdef),
202 m_mesh_update_thread(this),
204 new ClientMap(this, this, control,
205 device->getSceneManager()->getRootSceneNode(),
206 device->getSceneManager(), 666),
207 device->getSceneManager(),
210 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
212 m_server_ser_ver(SER_FMT_VER_INVALID),
214 m_inventory_updated(false),
217 m_password(password),
218 m_access_denied(false),
219 m_texture_receive_progress(0),
220 m_textures_received(false),
221 m_tooldef_received(false),
222 m_nodedef_received(false),
223 m_craftitemdef_received(false)
225 m_packetcounter_timer = 0.0;
226 //m_delete_unused_sectors_timer = 0.0;
227 m_connection_reinit_timer = 0.0;
228 m_avg_rtt_timer = 0.0;
229 m_playerpos_send_timer = 0.0;
230 m_ignore_damage_timer = 0.0;
232 // Build main texture atlas, now that the GameDef exists (that is, us)
233 if(g_settings->getBool("enable_texture_atlas"))
234 m_tsrc->buildMainAtlas(this);
236 infostream<<"Not building texture atlas."<<std::endl;
238 // Update node textures
239 m_nodedef->updateTextures(m_tsrc);
241 // Start threads after setting up content definitions
242 m_mesh_update_thread.Start();
248 Player *player = new LocalPlayer(this);
250 player->updateName(playername);
252 m_env.addPlayer(player);
254 // Initialize player in the inventory context
255 m_inventory_context.current_player = player;
262 //JMutexAutoLock conlock(m_con_mutex); //bulk comment-out
266 m_mesh_update_thread.setRun(false);
267 while(m_mesh_update_thread.IsRunning())
271 void Client::connect(Address address)
273 DSTACK(__FUNCTION_NAME);
274 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
275 m_con.SetTimeoutMs(0);
276 m_con.Connect(address);
279 bool Client::connectedAndInitialized()
281 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
283 if(m_con.Connected() == false)
286 if(m_server_ser_ver == SER_FMT_VER_INVALID)
292 void Client::step(float dtime)
294 DSTACK(__FUNCTION_NAME);
300 if(m_ignore_damage_timer > dtime)
301 m_ignore_damage_timer -= dtime;
303 m_ignore_damage_timer = 0.0;
305 //infostream<<"Client steps "<<dtime<<std::endl;
308 //TimeTaker timer("ReceiveAll()", m_device);
314 //TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device);
316 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
317 m_con.RunTimeouts(dtime);
324 float &counter = m_packetcounter_timer;
330 infostream<<"Client packetcounter (20s):"<<std::endl;
331 m_packetcounter.print(infostream);
332 m_packetcounter.clear();
336 // Get connection status
337 bool connected = connectedAndInitialized();
342 Delete unused sectors
344 NOTE: This jams the game for a while because deleting sectors
348 float &counter = m_delete_unused_sectors_timer;
356 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
358 core::list<v3s16> deleted_blocks;
360 float delete_unused_sectors_timeout =
361 g_settings->getFloat("client_delete_unused_sectors_timeout");
363 // Delete sector blocks
364 /*u32 num = m_env.getMap().unloadUnusedData
365 (delete_unused_sectors_timeout,
366 true, &deleted_blocks);*/
368 // Delete whole sectors
369 m_env.getMap().unloadUnusedData
370 (delete_unused_sectors_timeout,
373 if(deleted_blocks.size() > 0)
375 /*infostream<<"Client: Deleted blocks of "<<num
376 <<" unused sectors"<<std::endl;*/
377 /*infostream<<"Client: Deleted "<<num
378 <<" unused sectors"<<std::endl;*/
384 // Env is locked so con can be locked.
385 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
387 core::list<v3s16>::Iterator i = deleted_blocks.begin();
388 core::list<v3s16> sendlist;
391 if(sendlist.size() == 255 || i == deleted_blocks.end())
393 if(sendlist.size() == 0)
402 u32 replysize = 2+1+6*sendlist.size();
403 SharedBuffer<u8> reply(replysize);
404 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
405 reply[2] = sendlist.size();
407 for(core::list<v3s16>::Iterator
408 j = sendlist.begin();
409 j != sendlist.end(); j++)
411 writeV3S16(&reply[2+1+6*k], *j);
414 m_con.Send(PEER_ID_SERVER, 1, reply, true);
416 if(i == deleted_blocks.end())
422 sendlist.push_back(*i);
430 if(connected == false)
432 float &counter = m_connection_reinit_timer;
438 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
440 Player *myplayer = m_env.getLocalPlayer();
441 assert(myplayer != NULL);
443 // Send TOSERVER_INIT
444 // [0] u16 TOSERVER_INIT
445 // [2] u8 SER_FMT_VER_HIGHEST
446 // [3] u8[20] player_name
447 // [23] u8[28] password (new in some version)
448 // [51] u16 client network protocol version (new in some version)
449 SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2);
450 writeU16(&data[0], TOSERVER_INIT);
451 writeU8(&data[2], SER_FMT_VER_HIGHEST);
453 memset((char*)&data[3], 0, PLAYERNAME_SIZE);
454 snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
456 /*infostream<<"Client: sending initial password hash: \""<<m_password<<"\""
459 memset((char*)&data[23], 0, PASSWORD_SIZE);
460 snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
462 // This should be incremented in each version
463 writeU16(&data[51], PROTOCOL_VERSION);
465 // Send as unreliable
466 Send(0, data, false);
469 // Not connected, return
474 Do stuff if connected
478 Run Map's timers and unload unused data
480 const float map_timer_and_unload_dtime = 5.25;
481 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
483 ScopeProfiler sp(g_profiler, "Client: map timer and unload");
484 core::list<v3s16> deleted_blocks;
485 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
486 g_settings->getFloat("client_unload_unused_data_timeout"),
489 /*if(deleted_blocks.size() > 0)
490 infostream<<"Client: Unloaded "<<deleted_blocks.size()
491 <<" unused blocks"<<std::endl;*/
495 NOTE: This loop is intentionally iterated the way it is.
498 core::list<v3s16>::Iterator i = deleted_blocks.begin();
499 core::list<v3s16> sendlist;
502 if(sendlist.size() == 255 || i == deleted_blocks.end())
504 if(sendlist.size() == 0)
513 u32 replysize = 2+1+6*sendlist.size();
514 SharedBuffer<u8> reply(replysize);
515 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
516 reply[2] = sendlist.size();
518 for(core::list<v3s16>::Iterator
519 j = sendlist.begin();
520 j != sendlist.end(); j++)
522 writeV3S16(&reply[2+1+6*k], *j);
525 m_con.Send(PEER_ID_SERVER, 1, reply, true);
527 if(i == deleted_blocks.end())
533 sendlist.push_back(*i);
543 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
545 // Control local player (0ms)
546 LocalPlayer *player = m_env.getLocalPlayer();
547 assert(player != NULL);
548 player->applyControl(dtime);
550 //TimeTaker envtimer("env step", m_device);
559 ClientEnvEvent event = m_env.getClientEvent();
560 if(event.type == CEE_NONE)
564 else if(event.type == CEE_PLAYER_DAMAGE)
566 if(m_ignore_damage_timer <= 0)
568 u8 damage = event.player_damage.amount;
571 // Add to ClientEvent queue
573 event.type = CE_PLAYER_DAMAGE;
574 event.player_damage.amount = damage;
575 m_client_event_queue.push_back(event);
585 float &counter = m_avg_rtt_timer;
590 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
591 // connectedAndInitialized() is true, peer exists.
592 float avg_rtt = m_con.GetPeerAvgRTT(PEER_ID_SERVER);
593 infostream<<"Client: avg_rtt="<<avg_rtt<<std::endl;
598 Send player position to server
601 float &counter = m_playerpos_send_timer;
611 Replace updated meshes
614 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
616 //TimeTaker timer("** Processing mesh update result queue");
619 /*infostream<<"Mesh update result queue size is "
620 <<m_mesh_update_thread.m_queue_out.size()
623 while(m_mesh_update_thread.m_queue_out.size() > 0)
625 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
626 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
629 block->replaceMesh(r.mesh);
631 if(r.ack_block_to_server)
633 /*infostream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
634 <<","<<r.p.Z<<")"<<std::endl;*/
645 u32 replysize = 2+1+6;
646 SharedBuffer<u8> reply(replysize);
647 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
649 writeV3S16(&reply[3], r.p);
651 m_con.Send(PEER_ID_SERVER, 1, reply, true);
657 // Virtual methods from con::PeerHandler
658 void Client::peerAdded(con::Peer *peer)
660 infostream<<"Client::peerAdded(): peer->id="
661 <<peer->id<<std::endl;
663 void Client::deletingPeer(con::Peer *peer, bool timeout)
665 infostream<<"Client::deletingPeer(): "
666 "Server Peer is getting deleted "
667 <<"(timeout="<<timeout<<")"<<std::endl;
670 void Client::ReceiveAll()
672 DSTACK(__FUNCTION_NAME);
673 u32 start_ms = porting::getTimeMs();
676 // Limit time even if there would be huge amounts of data to
678 if(porting::getTimeMs() > start_ms + 100)
684 catch(con::NoIncomingDataException &e)
688 catch(con::InvalidIncomingDataException &e)
690 infostream<<"Client::ReceiveAll(): "
691 "InvalidIncomingDataException: what()="
692 <<e.what()<<std::endl;
697 void Client::Receive()
699 DSTACK(__FUNCTION_NAME);
700 SharedBuffer<u8> data;
704 //TimeTaker t1("con mutex and receive", m_device);
705 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
706 datasize = m_con.Receive(sender_peer_id, data);
708 //TimeTaker t1("ProcessData", m_device);
709 ProcessData(*data, datasize, sender_peer_id);
713 sender_peer_id given to this shall be quaranteed to be a valid peer
715 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
717 DSTACK(__FUNCTION_NAME);
719 // Ignore packets that don't even fit a command
722 m_packetcounter.add(60000);
726 ToClientCommand command = (ToClientCommand)readU16(&data[0]);
728 //infostream<<"Client: received command="<<command<<std::endl;
729 m_packetcounter.add((u16)command);
732 If this check is removed, be sure to change the queue
733 system to know the ids
735 if(sender_peer_id != PEER_ID_SERVER)
737 infostream<<"Client::ProcessData(): Discarding data not "
738 "coming from server: peer_id="<<sender_peer_id
743 u8 ser_version = m_server_ser_ver;
745 //infostream<<"Client received command="<<(int)command<<std::endl;
747 if(command == TOCLIENT_INIT)
752 u8 deployed = data[2];
754 infostream<<"Client: TOCLIENT_INIT received with "
755 "deployed="<<((int)deployed&0xff)<<std::endl;
757 if(deployed < SER_FMT_VER_LOWEST
758 || deployed > SER_FMT_VER_HIGHEST)
760 infostream<<"Client: TOCLIENT_INIT: Server sent "
761 <<"unsupported ser_fmt_ver"<<std::endl;
765 m_server_ser_ver = deployed;
767 // Get player position
768 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
769 if(datasize >= 2+1+6)
770 playerpos_s16 = readV3S16(&data[2+1]);
771 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
774 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
776 // Set player position
777 Player *player = m_env.getLocalPlayer();
778 assert(player != NULL);
779 player->setPosition(playerpos_f);
782 if(datasize >= 2+1+6+8)
785 m_map_seed = readU64(&data[2+1+6]);
786 infostream<<"Client: received map seed: "<<m_map_seed<<std::endl;
791 SharedBuffer<u8> reply(replysize);
792 writeU16(&reply[0], TOSERVER_INIT2);
794 m_con.Send(PEER_ID_SERVER, 1, reply, true);
799 if(command == TOCLIENT_ACCESS_DENIED)
801 // The server didn't like our password. Note, this needs
802 // to be processed even if the serialisation format has
803 // not been agreed yet, the same as TOCLIENT_INIT.
804 m_access_denied = true;
805 m_access_denied_reason = L"Unknown";
808 std::string datastring((char*)&data[2], datasize-2);
809 std::istringstream is(datastring, std::ios_base::binary);
810 m_access_denied_reason = deSerializeWideString(is);
815 if(ser_version == SER_FMT_VER_INVALID)
817 infostream<<"Client: Server serialization"
818 " format invalid or not initialized."
819 " Skipping incoming command="<<command<<std::endl;
823 // Just here to avoid putting the two if's together when
824 // making some copypasta
827 if(command == TOCLIENT_REMOVENODE)
832 p.X = readS16(&data[2]);
833 p.Y = readS16(&data[4]);
834 p.Z = readS16(&data[6]);
836 //TimeTaker t1("TOCLIENT_REMOVENODE");
838 // This will clear the cracking animation after digging
839 ((ClientMap&)m_env.getMap()).clearTempMod(p);
843 else if(command == TOCLIENT_ADDNODE)
845 if(datasize < 8 + MapNode::serializedLength(ser_version))
849 p.X = readS16(&data[2]);
850 p.Y = readS16(&data[4]);
851 p.Z = readS16(&data[6]);
853 //TimeTaker t1("TOCLIENT_ADDNODE");
856 n.deSerialize(&data[8], ser_version);
860 else if(command == TOCLIENT_BLOCKDATA)
862 // Ignore too small packet
867 p.X = readS16(&data[2]);
868 p.Y = readS16(&data[4]);
869 p.Z = readS16(&data[6]);
871 /*infostream<<"Client: Thread: BLOCKDATA for ("
872 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
873 /*infostream<<"Client: Thread: BLOCKDATA for ("
874 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
876 std::string datastring((char*)&data[8], datasize-8);
877 std::istringstream istr(datastring, std::ios_base::binary);
883 sector = m_env.getMap().emergeSector(p2d);
885 assert(sector->getPos() == p2d);
887 //TimeTaker timer("MapBlock deSerialize");
890 block = sector->getBlockNoCreateNoEx(p.Y);
894 Update an existing block
896 //infostream<<"Updating"<<std::endl;
897 block->deSerialize(istr, ser_version);
904 //infostream<<"Creating new"<<std::endl;
905 block = new MapBlock(&m_env.getMap(), p, this);
906 block->deSerialize(istr, ser_version);
907 sector->insertBlock(block);
921 u32 replysize = 2+1+6;
922 SharedBuffer<u8> reply(replysize);
923 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
925 writeV3S16(&reply[3], p);
927 m_con.Send(PEER_ID_SERVER, 1, reply, true);
931 Update Mesh of this block and blocks at x-, y- and z-.
932 Environment should not be locked as it interlocks with the
933 main thread, from which is will want to retrieve textures.
936 //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
938 Add it to mesh update queue and set it to be acknowledged after update.
940 //infostream<<"Adding mesh update task for received block"<<std::endl;
941 addUpdateMeshTaskWithEdge(p, true);
943 else if(command == TOCLIENT_PLAYERPOS)
945 infostream<<"Received deprecated TOCLIENT_PLAYERPOS"
949 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
950 our_peer_id = m_con.GetPeerID();
952 // Cancel if we don't have a peer id
953 if(our_peer_id == PEER_ID_INEXISTENT){
954 infostream<<"TOCLIENT_PLAYERPOS cancelled: "
961 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
963 u32 player_size = 2+12+12+4+4;
965 u32 player_count = (datasize-2) / player_size;
967 for(u32 i=0; i<player_count; i++)
969 u16 peer_id = readU16(&data[start]);
971 Player *player = m_env.getPlayer(peer_id);
973 // Skip if player doesn't exist
976 start += player_size;
980 // Skip if player is local player
981 if(player->isLocal())
983 start += player_size;
987 v3s32 ps = readV3S32(&data[start+2]);
988 v3s32 ss = readV3S32(&data[start+2+12]);
989 s32 pitch_i = readS32(&data[start+2+12+12]);
990 s32 yaw_i = readS32(&data[start+2+12+12+4]);
991 /*infostream<<"Client: got "
992 <<"pitch_i="<<pitch_i
993 <<" yaw_i="<<yaw_i<<std::endl;*/
994 f32 pitch = (f32)pitch_i / 100.0;
995 f32 yaw = (f32)yaw_i / 100.0;
996 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
997 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
998 player->setPosition(position);
999 player->setSpeed(speed);
1000 player->setPitch(pitch);
1001 player->setYaw(yaw);
1003 /*infostream<<"Client: player "<<peer_id
1005 <<" yaw="<<yaw<<std::endl;*/
1007 start += player_size;
1011 else if(command == TOCLIENT_PLAYERINFO)
1013 infostream<<"Client received DEPRECATED TOCLIENT_PLAYERINFO"<<std::endl;
1017 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1018 our_peer_id = m_con.GetPeerID();
1020 // Cancel if we don't have a peer id
1021 if(our_peer_id == PEER_ID_INEXISTENT){
1022 infostream<<"TOCLIENT_PLAYERINFO cancelled: "
1023 "we have no peer id"
1028 //infostream<<"Client: Server reports players:"<<std::endl;
1031 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1033 u32 item_size = 2+PLAYERNAME_SIZE;
1034 u32 player_count = (datasize-2) / item_size;
1037 core::list<u16> players_alive;
1038 for(u32 i=0; i<player_count; i++)
1040 // Make sure the name ends in '\0'
1041 data[start+2+20-1] = 0;
1043 u16 peer_id = readU16(&data[start]);
1045 players_alive.push_back(peer_id);
1047 /*infostream<<"peer_id="<<peer_id
1048 <<" name="<<((char*)&data[start+2])<<std::endl;*/
1050 // Don't update the info of the local player
1051 if(peer_id == our_peer_id)
1057 Player *player = m_env.getPlayer(peer_id);
1059 // Create a player if it doesn't exist
1062 player = new RemotePlayer(this,
1063 m_device->getSceneManager()->getRootSceneNode(),
1066 player->peer_id = peer_id;
1067 m_env.addPlayer(player);
1068 infostream<<"Client: Adding new player "
1069 <<peer_id<<std::endl;
1072 player->updateName((char*)&data[start+2]);
1078 Remove those players from the environment that
1079 weren't listed by the server.
1081 //infostream<<"Removing dead players"<<std::endl;
1082 core::list<Player*> players = m_env.getPlayers();
1083 core::list<Player*>::Iterator ip;
1084 for(ip=players.begin(); ip!=players.end(); ip++)
1086 // Ingore local player
1087 if((*ip)->isLocal())
1090 // Warn about a special case
1091 if((*ip)->peer_id == 0)
1093 infostream<<"Client: Removing "
1094 "dead player with id=0"<<std::endl;
1097 bool is_alive = false;
1098 core::list<u16>::Iterator i;
1099 for(i=players_alive.begin(); i!=players_alive.end(); i++)
1101 if((*ip)->peer_id == *i)
1107 /*infostream<<"peer_id="<<((*ip)->peer_id)
1108 <<" is_alive="<<is_alive<<std::endl;*/
1111 infostream<<"Removing dead player "<<(*ip)->peer_id
1113 m_env.removePlayer((*ip)->peer_id);
1118 else if(command == TOCLIENT_SECTORMETA)
1120 infostream<<"Client received DEPRECATED TOCLIENT_SECTORMETA"<<std::endl;
1125 [3...] v2s16 pos + sector metadata
1130 //infostream<<"Client received TOCLIENT_SECTORMETA"<<std::endl;
1133 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1135 std::string datastring((char*)&data[2], datasize-2);
1136 std::istringstream is(datastring, std::ios_base::binary);
1140 is.read((char*)buf, 1);
1141 u16 sector_count = readU8(buf);
1143 //infostream<<"sector_count="<<sector_count<<std::endl;
1145 for(u16 i=0; i<sector_count; i++)
1148 is.read((char*)buf, 4);
1149 v2s16 pos = readV2S16(buf);
1150 /*infostream<<"Client: deserializing sector at "
1151 <<"("<<pos.X<<","<<pos.Y<<")"<<std::endl;*/
1153 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
1154 ((ClientMap&)m_env.getMap()).deSerializeSector(pos, is);
1159 else if(command == TOCLIENT_INVENTORY)
1164 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
1167 //TimeTaker t2("mutex locking", m_device);
1168 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1171 //TimeTaker t3("istringstream init", m_device);
1172 std::string datastring((char*)&data[2], datasize-2);
1173 std::istringstream is(datastring, std::ios_base::binary);
1176 //m_env.printPlayers(infostream);
1178 //TimeTaker t4("player get", m_device);
1179 Player *player = m_env.getLocalPlayer();
1180 assert(player != NULL);
1183 //TimeTaker t1("inventory.deSerialize()", m_device);
1184 player->inventory.deSerialize(is, this);
1187 m_inventory_updated = true;
1189 //infostream<<"Client got player inventory:"<<std::endl;
1190 //player->inventory.print(infostream);
1194 else if(command == TOCLIENT_OBJECTDATA)
1196 // Strip command word and create a stringstream
1197 std::string datastring((char*)&data[2], datasize-2);
1198 std::istringstream is(datastring, std::ios_base::binary);
1206 is.read((char*)buf, 2);
1207 u16 playercount = readU16(buf);
1209 for(u16 i=0; i<playercount; i++)
1211 is.read((char*)buf, 2);
1212 u16 peer_id = readU16(buf);
1213 is.read((char*)buf, 12);
1214 v3s32 p_i = readV3S32(buf);
1215 is.read((char*)buf, 12);
1216 v3s32 s_i = readV3S32(buf);
1217 is.read((char*)buf, 4);
1218 s32 pitch_i = readS32(buf);
1219 is.read((char*)buf, 4);
1220 s32 yaw_i = readS32(buf);
1222 Player *player = m_env.getPlayer(peer_id);
1224 // Skip if player doesn't exist
1230 // Skip if player is local player
1231 if(player->isLocal())
1236 f32 pitch = (f32)pitch_i / 100.0;
1237 f32 yaw = (f32)yaw_i / 100.0;
1238 v3f position((f32)p_i.X/100., (f32)p_i.Y/100., (f32)p_i.Z/100.);
1239 v3f speed((f32)s_i.X/100., (f32)s_i.Y/100., (f32)s_i.Z/100.);
1241 player->setPosition(position);
1242 player->setSpeed(speed);
1243 player->setPitch(pitch);
1244 player->setYaw(yaw);
1249 NOTE: Deprecated stuff
1252 // Read active block count
1253 u16 blockcount = readU16(is);
1254 if(blockcount != 0){
1255 infostream<<"TOCLIENT_OBJECTDATA: blockcount != 0 "
1256 "not supported"<<std::endl;
1260 else if(command == TOCLIENT_TIME_OF_DAY)
1265 u16 time_of_day = readU16(&data[2]);
1266 time_of_day = time_of_day % 24000;
1267 //infostream<<"Client: time_of_day="<<time_of_day<<std::endl;
1275 m_env.setTimeOfDay(time_of_day);
1277 u32 dr = m_env.getDayNightRatio();
1279 infostream<<"Client: time_of_day="<<time_of_day
1285 else if(command == TOCLIENT_CHAT_MESSAGE)
1293 std::string datastring((char*)&data[2], datasize-2);
1294 std::istringstream is(datastring, std::ios_base::binary);
1297 is.read((char*)buf, 2);
1298 u16 len = readU16(buf);
1300 std::wstring message;
1301 for(u16 i=0; i<len; i++)
1303 is.read((char*)buf, 2);
1304 message += (wchar_t)readU16(buf);
1307 /*infostream<<"Client received chat message: "
1308 <<wide_to_narrow(message)<<std::endl;*/
1310 m_chat_queue.push_back(message);
1312 else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1314 //if(g_settings->getBool("enable_experimental"))
1318 u16 count of removed objects
1319 for all removed objects {
1322 u16 count of added objects
1323 for all added objects {
1326 u32 initialization data length
1327 string initialization data
1332 // Get all data except the command number
1333 std::string datastring((char*)&data[2], datasize-2);
1334 // Throw them in an istringstream
1335 std::istringstream is(datastring, std::ios_base::binary);
1339 // Read removed objects
1341 u16 removed_count = readU16((u8*)buf);
1342 for(u16 i=0; i<removed_count; i++)
1345 u16 id = readU16((u8*)buf);
1348 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1349 m_env.removeActiveObject(id);
1353 // Read added objects
1355 u16 added_count = readU16((u8*)buf);
1356 for(u16 i=0; i<added_count; i++)
1359 u16 id = readU16((u8*)buf);
1361 u8 type = readU8((u8*)buf);
1362 std::string data = deSerializeLongString(is);
1365 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1366 m_env.addActiveObject(id, type, data);
1371 else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1373 //if(g_settings->getBool("enable_experimental"))
1385 // Get all data except the command number
1386 std::string datastring((char*)&data[2], datasize-2);
1387 // Throw them in an istringstream
1388 std::istringstream is(datastring, std::ios_base::binary);
1390 while(is.eof() == false)
1394 u16 id = readU16((u8*)buf);
1398 u16 message_size = readU16((u8*)buf);
1399 std::string message;
1400 message.reserve(message_size);
1401 for(u16 i=0; i<message_size; i++)
1404 message.append(buf, 1);
1406 // Pass on to the environment
1408 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1409 m_env.processActiveObjectMessage(id, message);
1414 else if(command == TOCLIENT_HP)
1416 std::string datastring((char*)&data[2], datasize-2);
1417 std::istringstream is(datastring, std::ios_base::binary);
1418 Player *player = m_env.getLocalPlayer();
1419 assert(player != NULL);
1423 else if(command == TOCLIENT_MOVE_PLAYER)
1425 std::string datastring((char*)&data[2], datasize-2);
1426 std::istringstream is(datastring, std::ios_base::binary);
1427 Player *player = m_env.getLocalPlayer();
1428 assert(player != NULL);
1429 v3f pos = readV3F1000(is);
1430 f32 pitch = readF1000(is);
1431 f32 yaw = readF1000(is);
1432 player->setPosition(pos);
1433 /*player->setPitch(pitch);
1434 player->setYaw(yaw);*/
1436 infostream<<"Client got TOCLIENT_MOVE_PLAYER"
1437 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1443 Add to ClientEvent queue.
1444 This has to be sent to the main program because otherwise
1445 it would just force the pitch and yaw values to whatever
1446 the camera points to.
1449 event.type = CE_PLAYER_FORCE_MOVE;
1450 event.player_force_move.pitch = pitch;
1451 event.player_force_move.yaw = yaw;
1452 m_client_event_queue.push_back(event);
1454 // Ignore damage for a few seconds, so that the player doesn't
1455 // get damage from falling on ground
1456 m_ignore_damage_timer = 3.0;
1458 else if(command == TOCLIENT_PLAYERITEM)
1460 std::string datastring((char*)&data[2], datasize-2);
1461 std::istringstream is(datastring, std::ios_base::binary);
1463 u16 count = readU16(is);
1465 for (u16 i = 0; i < count; ++i) {
1466 u16 peer_id = readU16(is);
1467 Player *player = m_env.getPlayer(peer_id);
1471 infostream<<"Client: ignoring player item "
1472 << deSerializeString(is)
1473 << " for non-existing peer id " << peer_id
1476 } else if (player->isLocal()) {
1477 infostream<<"Client: ignoring player item "
1478 << deSerializeString(is)
1479 << " for local player" << std::endl;
1482 InventoryList *inv = player->inventory.getList("main");
1483 std::string itemstring(deSerializeString(is));
1484 if (itemstring.empty()) {
1487 <<"Client: empty player item for peer "
1488 << peer_id << std::endl;
1490 std::istringstream iss(itemstring);
1491 delete inv->changeItem(0,
1492 InventoryItem::deSerialize(iss, this));
1493 infostream<<"Client: player item for peer " << peer_id << ": ";
1494 player->getWieldItem()->serialize(infostream);
1495 infostream<<std::endl;
1500 else if(command == TOCLIENT_DEATHSCREEN)
1502 std::string datastring((char*)&data[2], datasize-2);
1503 std::istringstream is(datastring, std::ios_base::binary);
1505 bool set_camera_point_target = readU8(is);
1506 v3f camera_point_target = readV3F1000(is);
1509 event.type = CE_DEATHSCREEN;
1510 event.deathscreen.set_camera_point_target = set_camera_point_target;
1511 event.deathscreen.camera_point_target_x = camera_point_target.X;
1512 event.deathscreen.camera_point_target_y = camera_point_target.Y;
1513 event.deathscreen.camera_point_target_z = camera_point_target.Z;
1514 m_client_event_queue.push_back(event);
1516 else if(command == TOCLIENT_TEXTURES)
1518 io::IFileSystem *irrfs = m_device->getFileSystem();
1519 video::IVideoDriver *vdrv = m_device->getVideoDriver();
1521 std::string datastring((char*)&data[2], datasize-2);
1522 std::istringstream is(datastring, std::ios_base::binary);
1524 // Stop threads while updating content definitions
1525 m_mesh_update_thread.setRun(false);
1526 // Process the remaining TextureSource queue to let MeshUpdateThread
1527 // get it's remaining textures and thus let it stop
1528 while(m_mesh_update_thread.IsRunning()){
1529 m_tsrc->processQueue();
1534 u16 total number of texture bunches
1535 u16 index of this bunch
1536 u32 number of textures in this bunch
1544 int num_bunches = readU16(is);
1545 int bunch_i = readU16(is);
1546 m_texture_receive_progress = (float)bunch_i / (float)(num_bunches - 1);
1547 if(bunch_i == num_bunches - 1)
1548 m_textures_received = true;
1549 int num_textures = readU32(is);
1550 infostream<<"Client: Received textures: bunch "<<bunch_i<<"/"
1551 <<num_bunches<<" textures="<<num_textures
1552 <<" size="<<datasize<<std::endl;
1553 for(int i=0; i<num_textures; i++){
1554 std::string name = deSerializeString(is);
1555 std::string data = deSerializeLongString(is);
1556 // Silly irrlicht's const-incorrectness
1557 Buffer<char> data_rw(data.c_str(), data.size());
1558 // Create an irrlicht memory file
1559 io::IReadFile *rfile = irrfs->createMemoryReadFile(
1560 *data_rw, data.size(), "_tempreadfile");
1563 video::IImage *img = vdrv->createImageFromFile(rfile);
1565 errorstream<<"Client: Cannot create image from data of "
1566 <<"received texture \""<<name<<"\""<<std::endl;
1570 m_tsrc->insertSourceImage(name, img);
1575 if(m_nodedef_received && m_textures_received){
1576 // Rebuild inherited images and recreate textures
1577 m_tsrc->rebuildImagesAndTextures();
1579 // Update texture atlas
1580 if(g_settings->getBool("enable_texture_atlas"))
1581 m_tsrc->buildMainAtlas(this);
1583 // Update node textures
1584 m_nodedef->updateTextures(m_tsrc);
1588 m_mesh_update_thread.setRun(true);
1589 m_mesh_update_thread.Start();
1592 event.type = CE_TEXTURES_UPDATED;
1593 m_client_event_queue.push_back(event);
1595 else if(command == TOCLIENT_TOOLDEF)
1597 infostream<<"Client: Received tool definitions: packet size: "
1598 <<datasize<<std::endl;
1600 std::string datastring((char*)&data[2], datasize-2);
1601 std::istringstream is(datastring, std::ios_base::binary);
1603 m_tooldef_received = true;
1605 // Stop threads while updating content definitions
1606 m_mesh_update_thread.setRun(false);
1607 // Process the remaining TextureSource queue to let MeshUpdateThread
1608 // get it's remaining textures and thus let it stop
1609 while(m_mesh_update_thread.IsRunning()){
1610 m_tsrc->processQueue();
1613 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1614 m_tooldef->deSerialize(tmp_is);
1617 m_mesh_update_thread.setRun(true);
1618 m_mesh_update_thread.Start();
1620 else if(command == TOCLIENT_NODEDEF)
1622 infostream<<"Client: Received node definitions: packet size: "
1623 <<datasize<<std::endl;
1625 std::string datastring((char*)&data[2], datasize-2);
1626 std::istringstream is(datastring, std::ios_base::binary);
1628 m_nodedef_received = true;
1630 // Stop threads while updating content definitions
1631 m_mesh_update_thread.stop();
1633 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1634 m_nodedef->deSerialize(tmp_is, this);
1636 if(m_textures_received){
1637 // Update texture atlas
1638 if(g_settings->getBool("enable_texture_atlas"))
1639 m_tsrc->buildMainAtlas(this);
1641 // Update node textures
1642 m_nodedef->updateTextures(m_tsrc);
1646 m_mesh_update_thread.setRun(true);
1647 m_mesh_update_thread.Start();
1649 else if(command == TOCLIENT_CRAFTITEMDEF)
1651 infostream<<"Client: Received CraftItem definitions: packet size: "
1652 <<datasize<<std::endl;
1654 std::string datastring((char*)&data[2], datasize-2);
1655 std::istringstream is(datastring, std::ios_base::binary);
1657 m_craftitemdef_received = true;
1659 // Stop threads while updating content definitions
1660 m_mesh_update_thread.setRun(false);
1661 // Process the remaining TextureSource queue to let MeshUpdateThread
1662 // get it's remaining textures and thus let it stop
1663 while(m_mesh_update_thread.IsRunning()){
1664 m_tsrc->processQueue();
1667 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1668 m_craftitemdef->deSerialize(tmp_is);
1671 m_mesh_update_thread.setRun(true);
1672 m_mesh_update_thread.Start();
1676 infostream<<"Client: Ignoring unknown command "
1677 <<command<<std::endl;
1681 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1683 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1684 m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1687 void Client::interact(u8 action, const PointedThing& pointed)
1689 if(connectedAndInitialized() == false){
1690 infostream<<"Client::interact() "
1691 "cancelled (not connected)"
1696 std::ostringstream os(std::ios_base::binary);
1702 [5] u32 length of the next item
1703 [9] serialized PointedThing
1705 0: start digging (from undersurface) or use
1706 1: stop digging (all parameters ignored)
1707 2: digging completed
1708 3: place block or item (to abovesurface)
1711 writeU16(os, TOSERVER_INTERACT);
1712 writeU8(os, action);
1713 writeU16(os, getPlayerItem());
1714 std::ostringstream tmp_os(std::ios::binary);
1715 pointed.serialize(tmp_os);
1716 os<<serializeLongString(tmp_os.str());
1718 std::string s = os.str();
1719 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1722 Send(0, data, true);
1725 void Client::sendSignNodeText(v3s16 p, std::string text)
1733 std::ostringstream os(std::ios_base::binary);
1737 writeU16(buf, TOSERVER_SIGNNODETEXT);
1738 os.write((char*)buf, 2);
1742 os.write((char*)buf, 6);
1744 u16 textlen = text.size();
1745 // Write text length
1746 writeS16(buf, textlen);
1747 os.write((char*)buf, 2);
1750 os.write((char*)text.c_str(), textlen);
1753 std::string s = os.str();
1754 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1756 Send(0, data, true);
1759 void Client::sendInventoryAction(InventoryAction *a)
1761 std::ostringstream os(std::ios_base::binary);
1765 writeU16(buf, TOSERVER_INVENTORY_ACTION);
1766 os.write((char*)buf, 2);
1771 std::string s = os.str();
1772 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1774 Send(0, data, true);
1777 void Client::sendChatMessage(const std::wstring &message)
1779 std::ostringstream os(std::ios_base::binary);
1783 writeU16(buf, TOSERVER_CHAT_MESSAGE);
1784 os.write((char*)buf, 2);
1787 writeU16(buf, message.size());
1788 os.write((char*)buf, 2);
1791 for(u32 i=0; i<message.size(); i++)
1795 os.write((char*)buf, 2);
1799 std::string s = os.str();
1800 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1802 Send(0, data, true);
1805 void Client::sendChangePassword(const std::wstring oldpassword,
1806 const std::wstring newpassword)
1808 Player *player = m_env.getLocalPlayer();
1812 std::string playername = player->getName();
1813 std::string oldpwd = translatePassword(playername, oldpassword);
1814 std::string newpwd = translatePassword(playername, newpassword);
1816 std::ostringstream os(std::ios_base::binary);
1817 u8 buf[2+PASSWORD_SIZE*2];
1819 [0] u16 TOSERVER_PASSWORD
1820 [2] u8[28] old password
1821 [30] u8[28] new password
1824 writeU16(buf, TOSERVER_PASSWORD);
1825 for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1827 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1828 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1830 buf[2+PASSWORD_SIZE-1] = 0;
1831 buf[30+PASSWORD_SIZE-1] = 0;
1832 os.write((char*)buf, 2+PASSWORD_SIZE*2);
1835 std::string s = os.str();
1836 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1838 Send(0, data, true);
1842 void Client::sendDamage(u8 damage)
1844 DSTACK(__FUNCTION_NAME);
1845 std::ostringstream os(std::ios_base::binary);
1847 writeU16(os, TOSERVER_DAMAGE);
1848 writeU8(os, damage);
1851 std::string s = os.str();
1852 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1854 Send(0, data, true);
1857 void Client::sendRespawn()
1859 DSTACK(__FUNCTION_NAME);
1860 std::ostringstream os(std::ios_base::binary);
1862 writeU16(os, TOSERVER_RESPAWN);
1865 std::string s = os.str();
1866 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1868 Send(0, data, true);
1871 void Client::sendPlayerPos()
1873 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1875 Player *myplayer = m_env.getLocalPlayer();
1876 if(myplayer == NULL)
1881 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1882 our_peer_id = m_con.GetPeerID();
1885 // Set peer id if not set already
1886 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1887 myplayer->peer_id = our_peer_id;
1888 // Check that an existing peer_id is the same as the connection's
1889 assert(myplayer->peer_id == our_peer_id);
1891 v3f pf = myplayer->getPosition();
1892 v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1893 v3f sf = myplayer->getSpeed();
1894 v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1895 s32 pitch = myplayer->getPitch() * 100;
1896 s32 yaw = myplayer->getYaw() * 100;
1901 [2] v3s32 position*100
1902 [2+12] v3s32 speed*100
1903 [2+12+12] s32 pitch*100
1904 [2+12+12+4] s32 yaw*100
1907 SharedBuffer<u8> data(2+12+12+4+4);
1908 writeU16(&data[0], TOSERVER_PLAYERPOS);
1909 writeV3S32(&data[2], position);
1910 writeV3S32(&data[2+12], speed);
1911 writeS32(&data[2+12+12], pitch);
1912 writeS32(&data[2+12+12+4], yaw);
1914 // Send as unreliable
1915 Send(0, data, false);
1918 void Client::sendPlayerItem(u16 item)
1920 Player *myplayer = m_env.getLocalPlayer();
1921 if(myplayer == NULL)
1924 u16 our_peer_id = m_con.GetPeerID();
1926 // Set peer id if not set already
1927 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1928 myplayer->peer_id = our_peer_id;
1929 // Check that an existing peer_id is the same as the connection's
1930 assert(myplayer->peer_id == our_peer_id);
1932 SharedBuffer<u8> data(2+2);
1933 writeU16(&data[0], TOSERVER_PLAYERITEM);
1934 writeU16(&data[2], item);
1937 Send(0, data, true);
1940 void Client::removeNode(v3s16 p)
1942 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1944 core::map<v3s16, MapBlock*> modified_blocks;
1948 //TimeTaker t("removeNodeAndUpdate", m_device);
1949 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1951 catch(InvalidPositionException &e)
1955 for(core::map<v3s16, MapBlock * >::Iterator
1956 i = modified_blocks.getIterator();
1957 i.atEnd() == false; i++)
1959 v3s16 p = i.getNode()->getKey();
1960 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1961 addUpdateMeshTaskWithEdge(p);
1965 void Client::addNode(v3s16 p, MapNode n)
1967 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1969 TimeTaker timer1("Client::addNode()");
1971 core::map<v3s16, MapBlock*> modified_blocks;
1975 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1976 std::string st = std::string("");
1977 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st);
1979 catch(InvalidPositionException &e)
1982 //TimeTaker timer2("Client::addNode(): updateMeshes");
1984 for(core::map<v3s16, MapBlock * >::Iterator
1985 i = modified_blocks.getIterator();
1986 i.atEnd() == false; i++)
1988 v3s16 p = i.getNode()->getKey();
1989 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1990 addUpdateMeshTaskWithEdge(p);
1994 void Client::updateCamera(v3f pos, v3f dir, f32 fov)
1996 m_env.getClientMap().updateCamera(pos, dir, fov);
1999 void Client::renderPostFx()
2001 m_env.getClientMap().renderPostFx();
2004 MapNode Client::getNode(v3s16 p)
2006 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2007 return m_env.getMap().getNode(p);
2010 NodeMetadata* Client::getNodeMetadata(v3s16 p)
2012 return m_env.getMap().getNodeMetadata(p);
2015 LocalPlayer* Client::getLocalPlayer()
2017 return m_env.getLocalPlayer();
2020 void Client::setPlayerControl(PlayerControl &control)
2022 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2023 LocalPlayer *player = m_env.getLocalPlayer();
2024 assert(player != NULL);
2025 player->control = control;
2028 void Client::selectPlayerItem(u16 item)
2030 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2031 m_playeritem = item;
2032 m_inventory_updated = true;
2034 LocalPlayer *player = m_env.getLocalPlayer();
2035 assert(player != NULL);
2036 player->wieldItem(item);
2038 sendPlayerItem(item);
2041 // Returns true if the inventory of the local player has been
2042 // updated from the server. If it is true, it is set to false.
2043 bool Client::getLocalInventoryUpdated()
2045 // m_inventory_updated is behind envlock
2046 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2047 bool updated = m_inventory_updated;
2048 m_inventory_updated = false;
2052 // Copies the inventory of the local player to parameter
2053 void Client::getLocalInventory(Inventory &dst)
2055 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2056 Player *player = m_env.getLocalPlayer();
2057 assert(player != NULL);
2058 dst = player->inventory;
2061 InventoryContext *Client::getInventoryContext()
2063 return &m_inventory_context;
2066 Inventory* Client::getInventory(InventoryContext *c, std::string id)
2068 if(id == "current_player")
2070 assert(c->current_player);
2071 return &(c->current_player->inventory);
2075 std::string id0 = fn.next(":");
2077 if(id0 == "nodemeta")
2080 p.X = stoi(fn.next(","));
2081 p.Y = stoi(fn.next(","));
2082 p.Z = stoi(fn.next(","));
2083 NodeMetadata* meta = getNodeMetadata(p);
2085 return meta->getInventory();
2086 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
2087 <<"no metadata found"<<std::endl;
2091 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
2094 void Client::inventoryAction(InventoryAction *a)
2096 sendInventoryAction(a);
2099 ClientActiveObject * Client::getSelectedActiveObject(
2101 v3f from_pos_f_on_map,
2102 core::line3d<f32> shootline_on_map
2105 core::array<DistanceSortedActiveObject> objects;
2107 m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2109 //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2112 // After this, the closest object is the first in the array.
2115 for(u32 i=0; i<objects.size(); i++)
2117 ClientActiveObject *obj = objects[i].obj;
2119 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2120 if(selection_box == NULL)
2123 v3f pos = obj->getPosition();
2125 core::aabbox3d<f32> offsetted_box(
2126 selection_box->MinEdge + pos,
2127 selection_box->MaxEdge + pos
2130 if(offsetted_box.intersectsWithLine(shootline_on_map))
2132 //infostream<<"Returning selected object"<<std::endl;
2137 //infostream<<"No object selected; returning NULL."<<std::endl;
2141 void Client::printDebugInfo(std::ostream &os)
2143 //JMutexAutoLock lock1(m_fetchblock_mutex);
2144 /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2146 os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2147 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2148 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2152 u32 Client::getDayNightRatio()
2154 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2155 return m_env.getDayNightRatio();
2160 Player *player = m_env.getLocalPlayer();
2161 assert(player != NULL);
2165 void Client::setTempMod(v3s16 p, NodeMod mod)
2167 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2168 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2170 core::map<v3s16, MapBlock*> affected_blocks;
2171 ((ClientMap&)m_env.getMap()).setTempMod(p, mod,
2174 for(core::map<v3s16, MapBlock*>::Iterator
2175 i = affected_blocks.getIterator();
2176 i.atEnd() == false; i++)
2178 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2182 void Client::clearTempMod(v3s16 p)
2184 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2185 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2187 core::map<v3s16, MapBlock*> affected_blocks;
2188 ((ClientMap&)m_env.getMap()).clearTempMod(p,
2191 for(core::map<v3s16, MapBlock*>::Iterator
2192 i = affected_blocks.getIterator();
2193 i.atEnd() == false; i++)
2195 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2199 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
2201 /*infostream<<"Client::addUpdateMeshTask(): "
2202 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2205 MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2210 Create a task to update the mesh of the block
2213 MeshMakeData *data = new MeshMakeData;
2216 //TimeTaker timer("data fill");
2218 // Debug: 1-6ms, avg=2ms
2219 data->fill(getDayNightRatio(), b);
2223 //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2225 // Add task to queue
2226 m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server);
2228 /*infostream<<"Mesh update input queue size is "
2229 <<m_mesh_update_thread.m_queue_in.size()
2233 // Temporary test: make mesh directly in here
2235 //TimeTaker timer("make mesh");
2237 scene::SMesh *mesh_new = NULL;
2238 mesh_new = makeMapBlockMesh(data);
2239 b->replaceMesh(mesh_new);
2245 Mark mesh as non-expired at this point so that it can already
2246 be marked as expired again if the data changes
2248 b->setMeshExpired(false);
2251 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
2255 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2256 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2261 v3s16 p = blockpos + v3s16(0,0,0);
2262 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2263 addUpdateMeshTask(p, ack_to_server);
2265 catch(InvalidPositionException &e){}
2268 v3s16 p = blockpos + v3s16(-1,0,0);
2269 addUpdateMeshTask(p);
2271 catch(InvalidPositionException &e){}
2273 v3s16 p = blockpos + v3s16(0,-1,0);
2274 addUpdateMeshTask(p);
2276 catch(InvalidPositionException &e){}
2278 v3s16 p = blockpos + v3s16(0,0,-1);
2279 addUpdateMeshTask(p);
2281 catch(InvalidPositionException &e){}
2284 ClientEvent Client::getClientEvent()
2286 if(m_client_event_queue.size() == 0)
2289 event.type = CE_NONE;
2292 return m_client_event_queue.pop_front();
2295 float Client::getRTT(void)
2298 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2299 } catch(con::PeerNotFoundException &e){
2304 // IGameDef interface
2306 IToolDefManager* Client::getToolDefManager()
2310 INodeDefManager* Client::getNodeDefManager()
2314 ICraftDefManager* Client::getCraftDefManager()
2317 //return m_craftdef;
2319 ICraftItemDefManager* Client::getCraftItemDefManager()
2321 return m_craftitemdef;
2323 ITextureSource* Client::getTextureSource()
2327 u16 Client::allocateUnknownNodeId(const std::string &name)
2329 errorstream<<"Client::allocateUnknownNodeId(): "
2330 <<"Client cannot allocate node IDs"<<std::endl;
2332 return CONTENT_IGNORE;