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)
1015 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1016 our_peer_id = m_con.GetPeerID();
1018 // Cancel if we don't have a peer id
1019 if(our_peer_id == PEER_ID_INEXISTENT){
1020 infostream<<"TOCLIENT_PLAYERINFO cancelled: "
1021 "we have no peer id"
1026 //infostream<<"Client: Server reports players:"<<std::endl;
1029 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1031 u32 item_size = 2+PLAYERNAME_SIZE;
1032 u32 player_count = (datasize-2) / item_size;
1035 core::list<u16> players_alive;
1036 for(u32 i=0; i<player_count; i++)
1038 // Make sure the name ends in '\0'
1039 data[start+2+20-1] = 0;
1041 u16 peer_id = readU16(&data[start]);
1043 players_alive.push_back(peer_id);
1045 /*infostream<<"peer_id="<<peer_id
1046 <<" name="<<((char*)&data[start+2])<<std::endl;*/
1048 // Don't update the info of the local player
1049 if(peer_id == our_peer_id)
1055 Player *player = m_env.getPlayer(peer_id);
1057 // Create a player if it doesn't exist
1060 player = new RemotePlayer(this,
1061 m_device->getSceneManager()->getRootSceneNode(),
1064 player->peer_id = peer_id;
1065 m_env.addPlayer(player);
1066 infostream<<"Client: Adding new player "
1067 <<peer_id<<std::endl;
1070 player->updateName((char*)&data[start+2]);
1076 Remove those players from the environment that
1077 weren't listed by the server.
1079 //infostream<<"Removing dead players"<<std::endl;
1080 core::list<Player*> players = m_env.getPlayers();
1081 core::list<Player*>::Iterator ip;
1082 for(ip=players.begin(); ip!=players.end(); ip++)
1084 // Ingore local player
1085 if((*ip)->isLocal())
1088 // Warn about a special case
1089 if((*ip)->peer_id == 0)
1091 infostream<<"Client: Removing "
1092 "dead player with id=0"<<std::endl;
1095 bool is_alive = false;
1096 core::list<u16>::Iterator i;
1097 for(i=players_alive.begin(); i!=players_alive.end(); i++)
1099 if((*ip)->peer_id == *i)
1105 /*infostream<<"peer_id="<<((*ip)->peer_id)
1106 <<" is_alive="<<is_alive<<std::endl;*/
1109 infostream<<"Removing dead player "<<(*ip)->peer_id
1111 m_env.removePlayer((*ip)->peer_id);
1115 else if(command == TOCLIENT_SECTORMETA)
1117 infostream<<"Client received DEPRECATED TOCLIENT_SECTORMETA"<<std::endl;
1122 [3...] v2s16 pos + sector metadata
1127 //infostream<<"Client received TOCLIENT_SECTORMETA"<<std::endl;
1130 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1132 std::string datastring((char*)&data[2], datasize-2);
1133 std::istringstream is(datastring, std::ios_base::binary);
1137 is.read((char*)buf, 1);
1138 u16 sector_count = readU8(buf);
1140 //infostream<<"sector_count="<<sector_count<<std::endl;
1142 for(u16 i=0; i<sector_count; i++)
1145 is.read((char*)buf, 4);
1146 v2s16 pos = readV2S16(buf);
1147 /*infostream<<"Client: deserializing sector at "
1148 <<"("<<pos.X<<","<<pos.Y<<")"<<std::endl;*/
1150 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
1151 ((ClientMap&)m_env.getMap()).deSerializeSector(pos, is);
1156 else if(command == TOCLIENT_INVENTORY)
1161 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
1164 //TimeTaker t2("mutex locking", m_device);
1165 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1168 //TimeTaker t3("istringstream init", m_device);
1169 std::string datastring((char*)&data[2], datasize-2);
1170 std::istringstream is(datastring, std::ios_base::binary);
1173 //m_env.printPlayers(infostream);
1175 //TimeTaker t4("player get", m_device);
1176 Player *player = m_env.getLocalPlayer();
1177 assert(player != NULL);
1180 //TimeTaker t1("inventory.deSerialize()", m_device);
1181 player->inventory.deSerialize(is, this);
1184 m_inventory_updated = true;
1186 //infostream<<"Client got player inventory:"<<std::endl;
1187 //player->inventory.print(infostream);
1191 else if(command == TOCLIENT_OBJECTDATA)
1193 // Strip command word and create a stringstream
1194 std::string datastring((char*)&data[2], datasize-2);
1195 std::istringstream is(datastring, std::ios_base::binary);
1203 is.read((char*)buf, 2);
1204 u16 playercount = readU16(buf);
1206 for(u16 i=0; i<playercount; i++)
1208 is.read((char*)buf, 2);
1209 u16 peer_id = readU16(buf);
1210 is.read((char*)buf, 12);
1211 v3s32 p_i = readV3S32(buf);
1212 is.read((char*)buf, 12);
1213 v3s32 s_i = readV3S32(buf);
1214 is.read((char*)buf, 4);
1215 s32 pitch_i = readS32(buf);
1216 is.read((char*)buf, 4);
1217 s32 yaw_i = readS32(buf);
1219 Player *player = m_env.getPlayer(peer_id);
1221 // Skip if player doesn't exist
1227 // Skip if player is local player
1228 if(player->isLocal())
1233 f32 pitch = (f32)pitch_i / 100.0;
1234 f32 yaw = (f32)yaw_i / 100.0;
1235 v3f position((f32)p_i.X/100., (f32)p_i.Y/100., (f32)p_i.Z/100.);
1236 v3f speed((f32)s_i.X/100., (f32)s_i.Y/100., (f32)s_i.Z/100.);
1238 player->setPosition(position);
1239 player->setSpeed(speed);
1240 player->setPitch(pitch);
1241 player->setYaw(yaw);
1246 NOTE: Deprecated stuff
1249 // Read active block count
1250 u16 blockcount = readU16(is);
1251 if(blockcount != 0){
1252 infostream<<"TOCLIENT_OBJECTDATA: blockcount != 0 "
1253 "not supported"<<std::endl;
1257 else if(command == TOCLIENT_TIME_OF_DAY)
1262 u16 time_of_day = readU16(&data[2]);
1263 time_of_day = time_of_day % 24000;
1264 //infostream<<"Client: time_of_day="<<time_of_day<<std::endl;
1272 m_env.setTimeOfDay(time_of_day);
1274 u32 dr = m_env.getDayNightRatio();
1276 infostream<<"Client: time_of_day="<<time_of_day
1282 else if(command == TOCLIENT_CHAT_MESSAGE)
1290 std::string datastring((char*)&data[2], datasize-2);
1291 std::istringstream is(datastring, std::ios_base::binary);
1294 is.read((char*)buf, 2);
1295 u16 len = readU16(buf);
1297 std::wstring message;
1298 for(u16 i=0; i<len; i++)
1300 is.read((char*)buf, 2);
1301 message += (wchar_t)readU16(buf);
1304 /*infostream<<"Client received chat message: "
1305 <<wide_to_narrow(message)<<std::endl;*/
1307 m_chat_queue.push_back(message);
1309 else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1311 //if(g_settings->getBool("enable_experimental"))
1315 u16 count of removed objects
1316 for all removed objects {
1319 u16 count of added objects
1320 for all added objects {
1323 u32 initialization data length
1324 string initialization data
1329 // Get all data except the command number
1330 std::string datastring((char*)&data[2], datasize-2);
1331 // Throw them in an istringstream
1332 std::istringstream is(datastring, std::ios_base::binary);
1336 // Read removed objects
1338 u16 removed_count = readU16((u8*)buf);
1339 for(u16 i=0; i<removed_count; i++)
1342 u16 id = readU16((u8*)buf);
1345 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1346 m_env.removeActiveObject(id);
1350 // Read added objects
1352 u16 added_count = readU16((u8*)buf);
1353 for(u16 i=0; i<added_count; i++)
1356 u16 id = readU16((u8*)buf);
1358 u8 type = readU8((u8*)buf);
1359 std::string data = deSerializeLongString(is);
1362 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1363 m_env.addActiveObject(id, type, data);
1368 else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1370 //if(g_settings->getBool("enable_experimental"))
1382 // Get all data except the command number
1383 std::string datastring((char*)&data[2], datasize-2);
1384 // Throw them in an istringstream
1385 std::istringstream is(datastring, std::ios_base::binary);
1387 while(is.eof() == false)
1391 u16 id = readU16((u8*)buf);
1395 u16 message_size = readU16((u8*)buf);
1396 std::string message;
1397 message.reserve(message_size);
1398 for(u16 i=0; i<message_size; i++)
1401 message.append(buf, 1);
1403 // Pass on to the environment
1405 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1406 m_env.processActiveObjectMessage(id, message);
1411 else if(command == TOCLIENT_HP)
1413 std::string datastring((char*)&data[2], datasize-2);
1414 std::istringstream is(datastring, std::ios_base::binary);
1415 Player *player = m_env.getLocalPlayer();
1416 assert(player != NULL);
1420 else if(command == TOCLIENT_MOVE_PLAYER)
1422 std::string datastring((char*)&data[2], datasize-2);
1423 std::istringstream is(datastring, std::ios_base::binary);
1424 Player *player = m_env.getLocalPlayer();
1425 assert(player != NULL);
1426 v3f pos = readV3F1000(is);
1427 f32 pitch = readF1000(is);
1428 f32 yaw = readF1000(is);
1429 player->setPosition(pos);
1430 /*player->setPitch(pitch);
1431 player->setYaw(yaw);*/
1433 infostream<<"Client got TOCLIENT_MOVE_PLAYER"
1434 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1440 Add to ClientEvent queue.
1441 This has to be sent to the main program because otherwise
1442 it would just force the pitch and yaw values to whatever
1443 the camera points to.
1446 event.type = CE_PLAYER_FORCE_MOVE;
1447 event.player_force_move.pitch = pitch;
1448 event.player_force_move.yaw = yaw;
1449 m_client_event_queue.push_back(event);
1451 // Ignore damage for a few seconds, so that the player doesn't
1452 // get damage from falling on ground
1453 m_ignore_damage_timer = 3.0;
1455 else if(command == TOCLIENT_PLAYERITEM)
1457 std::string datastring((char*)&data[2], datasize-2);
1458 std::istringstream is(datastring, std::ios_base::binary);
1460 u16 count = readU16(is);
1462 for (u16 i = 0; i < count; ++i) {
1463 u16 peer_id = readU16(is);
1464 Player *player = m_env.getPlayer(peer_id);
1468 infostream<<"Client: ignoring player item "
1469 << deSerializeString(is)
1470 << " for non-existing peer id " << peer_id
1473 } else if (player->isLocal()) {
1474 infostream<<"Client: ignoring player item "
1475 << deSerializeString(is)
1476 << " for local player" << std::endl;
1479 InventoryList *inv = player->inventory.getList("main");
1480 std::string itemstring(deSerializeString(is));
1481 if (itemstring.empty()) {
1484 <<"Client: empty player item for peer "
1485 << peer_id << std::endl;
1487 std::istringstream iss(itemstring);
1488 delete inv->changeItem(0,
1489 InventoryItem::deSerialize(iss, this));
1490 infostream<<"Client: player item for peer " << peer_id << ": ";
1491 player->getWieldItem()->serialize(infostream);
1492 infostream<<std::endl;
1497 else if(command == TOCLIENT_DEATHSCREEN)
1499 std::string datastring((char*)&data[2], datasize-2);
1500 std::istringstream is(datastring, std::ios_base::binary);
1502 bool set_camera_point_target = readU8(is);
1503 v3f camera_point_target = readV3F1000(is);
1506 event.type = CE_DEATHSCREEN;
1507 event.deathscreen.set_camera_point_target = set_camera_point_target;
1508 event.deathscreen.camera_point_target_x = camera_point_target.X;
1509 event.deathscreen.camera_point_target_y = camera_point_target.Y;
1510 event.deathscreen.camera_point_target_z = camera_point_target.Z;
1511 m_client_event_queue.push_back(event);
1513 else if(command == TOCLIENT_TEXTURES)
1515 io::IFileSystem *irrfs = m_device->getFileSystem();
1516 video::IVideoDriver *vdrv = m_device->getVideoDriver();
1518 std::string datastring((char*)&data[2], datasize-2);
1519 std::istringstream is(datastring, std::ios_base::binary);
1521 // Stop threads while updating content definitions
1522 m_mesh_update_thread.setRun(false);
1523 // Process the remaining TextureSource queue to let MeshUpdateThread
1524 // get it's remaining textures and thus let it stop
1525 while(m_mesh_update_thread.IsRunning()){
1526 m_tsrc->processQueue();
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.setRun(false);
1604 // Process the remaining TextureSource queue to let MeshUpdateThread
1605 // get it's remaining textures and thus let it stop
1606 while(m_mesh_update_thread.IsRunning()){
1607 m_tsrc->processQueue();
1610 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1611 m_tooldef->deSerialize(tmp_is);
1614 m_mesh_update_thread.setRun(true);
1615 m_mesh_update_thread.Start();
1617 else if(command == TOCLIENT_NODEDEF)
1619 infostream<<"Client: Received node definitions: packet size: "
1620 <<datasize<<std::endl;
1622 std::string datastring((char*)&data[2], datasize-2);
1623 std::istringstream is(datastring, std::ios_base::binary);
1625 m_nodedef_received = true;
1627 // Stop threads while updating content definitions
1628 m_mesh_update_thread.stop();
1630 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1631 m_nodedef->deSerialize(tmp_is, this);
1633 if(m_textures_received){
1634 // Update texture atlas
1635 if(g_settings->getBool("enable_texture_atlas"))
1636 m_tsrc->buildMainAtlas(this);
1638 // Update node textures
1639 m_nodedef->updateTextures(m_tsrc);
1643 m_mesh_update_thread.setRun(true);
1644 m_mesh_update_thread.Start();
1646 else if(command == TOCLIENT_CRAFTITEMDEF)
1648 infostream<<"Client: Received CraftItem definitions: packet size: "
1649 <<datasize<<std::endl;
1651 std::string datastring((char*)&data[2], datasize-2);
1652 std::istringstream is(datastring, std::ios_base::binary);
1654 m_craftitemdef_received = true;
1656 // Stop threads while updating content definitions
1657 m_mesh_update_thread.setRun(false);
1658 // Process the remaining TextureSource queue to let MeshUpdateThread
1659 // get it's remaining textures and thus let it stop
1660 while(m_mesh_update_thread.IsRunning()){
1661 m_tsrc->processQueue();
1664 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1665 m_craftitemdef->deSerialize(tmp_is);
1668 m_mesh_update_thread.setRun(true);
1669 m_mesh_update_thread.Start();
1673 infostream<<"Client: Ignoring unknown command "
1674 <<command<<std::endl;
1678 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1680 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1681 m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1684 void Client::interact(u8 action, const PointedThing& pointed)
1686 if(connectedAndInitialized() == false){
1687 infostream<<"Client::interact() "
1688 "cancelled (not connected)"
1693 std::ostringstream os(std::ios_base::binary);
1699 [5] u32 length of the next item
1700 [9] serialized PointedThing
1702 0: start digging (from undersurface) or use
1703 1: stop digging (all parameters ignored)
1704 2: digging completed
1705 3: place block or item (to abovesurface)
1708 writeU16(os, TOSERVER_INTERACT);
1709 writeU8(os, action);
1710 writeU16(os, getPlayerItem());
1711 std::ostringstream tmp_os(std::ios::binary);
1712 pointed.serialize(tmp_os);
1713 os<<serializeLongString(tmp_os.str());
1715 std::string s = os.str();
1716 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1719 Send(0, data, true);
1722 void Client::sendSignNodeText(v3s16 p, std::string text)
1730 std::ostringstream os(std::ios_base::binary);
1734 writeU16(buf, TOSERVER_SIGNNODETEXT);
1735 os.write((char*)buf, 2);
1739 os.write((char*)buf, 6);
1741 u16 textlen = text.size();
1742 // Write text length
1743 writeS16(buf, textlen);
1744 os.write((char*)buf, 2);
1747 os.write((char*)text.c_str(), textlen);
1750 std::string s = os.str();
1751 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1753 Send(0, data, true);
1756 void Client::sendInventoryAction(InventoryAction *a)
1758 std::ostringstream os(std::ios_base::binary);
1762 writeU16(buf, TOSERVER_INVENTORY_ACTION);
1763 os.write((char*)buf, 2);
1768 std::string s = os.str();
1769 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1771 Send(0, data, true);
1774 void Client::sendChatMessage(const std::wstring &message)
1776 std::ostringstream os(std::ios_base::binary);
1780 writeU16(buf, TOSERVER_CHAT_MESSAGE);
1781 os.write((char*)buf, 2);
1784 writeU16(buf, message.size());
1785 os.write((char*)buf, 2);
1788 for(u32 i=0; i<message.size(); i++)
1792 os.write((char*)buf, 2);
1796 std::string s = os.str();
1797 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1799 Send(0, data, true);
1802 void Client::sendChangePassword(const std::wstring oldpassword,
1803 const std::wstring newpassword)
1805 Player *player = m_env.getLocalPlayer();
1809 std::string playername = player->getName();
1810 std::string oldpwd = translatePassword(playername, oldpassword);
1811 std::string newpwd = translatePassword(playername, newpassword);
1813 std::ostringstream os(std::ios_base::binary);
1814 u8 buf[2+PASSWORD_SIZE*2];
1816 [0] u16 TOSERVER_PASSWORD
1817 [2] u8[28] old password
1818 [30] u8[28] new password
1821 writeU16(buf, TOSERVER_PASSWORD);
1822 for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1824 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1825 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1827 buf[2+PASSWORD_SIZE-1] = 0;
1828 buf[30+PASSWORD_SIZE-1] = 0;
1829 os.write((char*)buf, 2+PASSWORD_SIZE*2);
1832 std::string s = os.str();
1833 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1835 Send(0, data, true);
1839 void Client::sendDamage(u8 damage)
1841 DSTACK(__FUNCTION_NAME);
1842 std::ostringstream os(std::ios_base::binary);
1844 writeU16(os, TOSERVER_DAMAGE);
1845 writeU8(os, damage);
1848 std::string s = os.str();
1849 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1851 Send(0, data, true);
1854 void Client::sendRespawn()
1856 DSTACK(__FUNCTION_NAME);
1857 std::ostringstream os(std::ios_base::binary);
1859 writeU16(os, TOSERVER_RESPAWN);
1862 std::string s = os.str();
1863 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1865 Send(0, data, true);
1868 void Client::sendPlayerPos()
1870 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1872 Player *myplayer = m_env.getLocalPlayer();
1873 if(myplayer == NULL)
1878 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1879 our_peer_id = m_con.GetPeerID();
1882 // Set peer id if not set already
1883 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1884 myplayer->peer_id = our_peer_id;
1885 // Check that an existing peer_id is the same as the connection's
1886 assert(myplayer->peer_id == our_peer_id);
1888 v3f pf = myplayer->getPosition();
1889 v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1890 v3f sf = myplayer->getSpeed();
1891 v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1892 s32 pitch = myplayer->getPitch() * 100;
1893 s32 yaw = myplayer->getYaw() * 100;
1898 [2] v3s32 position*100
1899 [2+12] v3s32 speed*100
1900 [2+12+12] s32 pitch*100
1901 [2+12+12+4] s32 yaw*100
1904 SharedBuffer<u8> data(2+12+12+4+4);
1905 writeU16(&data[0], TOSERVER_PLAYERPOS);
1906 writeV3S32(&data[2], position);
1907 writeV3S32(&data[2+12], speed);
1908 writeS32(&data[2+12+12], pitch);
1909 writeS32(&data[2+12+12+4], yaw);
1911 // Send as unreliable
1912 Send(0, data, false);
1915 void Client::sendPlayerItem(u16 item)
1917 Player *myplayer = m_env.getLocalPlayer();
1918 if(myplayer == NULL)
1921 u16 our_peer_id = m_con.GetPeerID();
1923 // Set peer id if not set already
1924 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1925 myplayer->peer_id = our_peer_id;
1926 // Check that an existing peer_id is the same as the connection's
1927 assert(myplayer->peer_id == our_peer_id);
1929 SharedBuffer<u8> data(2+2);
1930 writeU16(&data[0], TOSERVER_PLAYERITEM);
1931 writeU16(&data[2], item);
1934 Send(0, data, true);
1937 void Client::removeNode(v3s16 p)
1939 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1941 core::map<v3s16, MapBlock*> modified_blocks;
1945 //TimeTaker t("removeNodeAndUpdate", m_device);
1946 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1948 catch(InvalidPositionException &e)
1952 for(core::map<v3s16, MapBlock * >::Iterator
1953 i = modified_blocks.getIterator();
1954 i.atEnd() == false; i++)
1956 v3s16 p = i.getNode()->getKey();
1957 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1958 addUpdateMeshTaskWithEdge(p);
1962 void Client::addNode(v3s16 p, MapNode n)
1964 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1966 TimeTaker timer1("Client::addNode()");
1968 core::map<v3s16, MapBlock*> modified_blocks;
1972 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1973 std::string st = std::string("");
1974 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st);
1976 catch(InvalidPositionException &e)
1979 //TimeTaker timer2("Client::addNode(): updateMeshes");
1981 for(core::map<v3s16, MapBlock * >::Iterator
1982 i = modified_blocks.getIterator();
1983 i.atEnd() == false; i++)
1985 v3s16 p = i.getNode()->getKey();
1986 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1987 addUpdateMeshTaskWithEdge(p);
1991 void Client::updateCamera(v3f pos, v3f dir, f32 fov)
1993 m_env.getClientMap().updateCamera(pos, dir, fov);
1996 void Client::renderPostFx()
1998 m_env.getClientMap().renderPostFx();
2001 MapNode Client::getNode(v3s16 p)
2003 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2004 return m_env.getMap().getNode(p);
2007 NodeMetadata* Client::getNodeMetadata(v3s16 p)
2009 return m_env.getMap().getNodeMetadata(p);
2012 LocalPlayer* Client::getLocalPlayer()
2014 return m_env.getLocalPlayer();
2017 void Client::setPlayerControl(PlayerControl &control)
2019 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2020 LocalPlayer *player = m_env.getLocalPlayer();
2021 assert(player != NULL);
2022 player->control = control;
2025 void Client::selectPlayerItem(u16 item)
2027 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2028 m_playeritem = item;
2029 m_inventory_updated = true;
2031 LocalPlayer *player = m_env.getLocalPlayer();
2032 assert(player != NULL);
2033 player->wieldItem(item);
2035 sendPlayerItem(item);
2038 // Returns true if the inventory of the local player has been
2039 // updated from the server. If it is true, it is set to false.
2040 bool Client::getLocalInventoryUpdated()
2042 // m_inventory_updated is behind envlock
2043 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2044 bool updated = m_inventory_updated;
2045 m_inventory_updated = false;
2049 // Copies the inventory of the local player to parameter
2050 void Client::getLocalInventory(Inventory &dst)
2052 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2053 Player *player = m_env.getLocalPlayer();
2054 assert(player != NULL);
2055 dst = player->inventory;
2058 InventoryContext *Client::getInventoryContext()
2060 return &m_inventory_context;
2063 Inventory* Client::getInventory(InventoryContext *c, std::string id)
2065 if(id == "current_player")
2067 assert(c->current_player);
2068 return &(c->current_player->inventory);
2072 std::string id0 = fn.next(":");
2074 if(id0 == "nodemeta")
2077 p.X = stoi(fn.next(","));
2078 p.Y = stoi(fn.next(","));
2079 p.Z = stoi(fn.next(","));
2080 NodeMetadata* meta = getNodeMetadata(p);
2082 return meta->getInventory();
2083 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
2084 <<"no metadata found"<<std::endl;
2088 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
2091 void Client::inventoryAction(InventoryAction *a)
2093 sendInventoryAction(a);
2096 ClientActiveObject * Client::getSelectedActiveObject(
2098 v3f from_pos_f_on_map,
2099 core::line3d<f32> shootline_on_map
2102 core::array<DistanceSortedActiveObject> objects;
2104 m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2106 //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2109 // After this, the closest object is the first in the array.
2112 for(u32 i=0; i<objects.size(); i++)
2114 ClientActiveObject *obj = objects[i].obj;
2116 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2117 if(selection_box == NULL)
2120 v3f pos = obj->getPosition();
2122 core::aabbox3d<f32> offsetted_box(
2123 selection_box->MinEdge + pos,
2124 selection_box->MaxEdge + pos
2127 if(offsetted_box.intersectsWithLine(shootline_on_map))
2129 //infostream<<"Returning selected object"<<std::endl;
2134 //infostream<<"No object selected; returning NULL."<<std::endl;
2138 void Client::printDebugInfo(std::ostream &os)
2140 //JMutexAutoLock lock1(m_fetchblock_mutex);
2141 /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2143 os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2144 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2145 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2149 u32 Client::getDayNightRatio()
2151 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2152 return m_env.getDayNightRatio();
2157 Player *player = m_env.getLocalPlayer();
2158 assert(player != NULL);
2162 void Client::setTempMod(v3s16 p, NodeMod mod)
2164 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2165 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2167 core::map<v3s16, MapBlock*> affected_blocks;
2168 ((ClientMap&)m_env.getMap()).setTempMod(p, mod,
2171 for(core::map<v3s16, MapBlock*>::Iterator
2172 i = affected_blocks.getIterator();
2173 i.atEnd() == false; i++)
2175 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2179 void Client::clearTempMod(v3s16 p)
2181 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2182 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2184 core::map<v3s16, MapBlock*> affected_blocks;
2185 ((ClientMap&)m_env.getMap()).clearTempMod(p,
2188 for(core::map<v3s16, MapBlock*>::Iterator
2189 i = affected_blocks.getIterator();
2190 i.atEnd() == false; i++)
2192 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2196 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
2198 /*infostream<<"Client::addUpdateMeshTask(): "
2199 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2202 MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2207 Create a task to update the mesh of the block
2210 MeshMakeData *data = new MeshMakeData;
2213 //TimeTaker timer("data fill");
2215 // Debug: 1-6ms, avg=2ms
2216 data->fill(getDayNightRatio(), b);
2220 //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2222 // Add task to queue
2223 m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server);
2225 /*infostream<<"Mesh update input queue size is "
2226 <<m_mesh_update_thread.m_queue_in.size()
2230 // Temporary test: make mesh directly in here
2232 //TimeTaker timer("make mesh");
2234 scene::SMesh *mesh_new = NULL;
2235 mesh_new = makeMapBlockMesh(data);
2236 b->replaceMesh(mesh_new);
2242 Mark mesh as non-expired at this point so that it can already
2243 be marked as expired again if the data changes
2245 b->setMeshExpired(false);
2248 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
2252 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2253 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2258 v3s16 p = blockpos + v3s16(0,0,0);
2259 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2260 addUpdateMeshTask(p, ack_to_server);
2262 catch(InvalidPositionException &e){}
2265 v3s16 p = blockpos + v3s16(-1,0,0);
2266 addUpdateMeshTask(p);
2268 catch(InvalidPositionException &e){}
2270 v3s16 p = blockpos + v3s16(0,-1,0);
2271 addUpdateMeshTask(p);
2273 catch(InvalidPositionException &e){}
2275 v3s16 p = blockpos + v3s16(0,0,-1);
2276 addUpdateMeshTask(p);
2278 catch(InvalidPositionException &e){}
2281 ClientEvent Client::getClientEvent()
2283 if(m_client_event_queue.size() == 0)
2286 event.type = CE_NONE;
2289 return m_client_event_queue.pop_front();
2292 float Client::getRTT(void)
2295 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2296 } catch(con::PeerNotFoundException &e){
2301 // IGameDef interface
2303 IToolDefManager* Client::getToolDefManager()
2307 INodeDefManager* Client::getNodeDefManager()
2311 ICraftDefManager* Client::getCraftDefManager()
2314 //return m_craftdef;
2316 ICraftItemDefManager* Client::getCraftItemDefManager()
2318 return m_craftitemdef;
2320 ITextureSource* Client::getTextureSource()
2324 u16 Client::allocateUnknownNodeId(const std::string &name)
2326 errorstream<<"Client::allocateUnknownNodeId(): "
2327 <<"Client cannot allocate node IDs"<<std::endl;
2329 return CONTENT_IGNORE;