3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "clientserver.h"
24 #include "jmutexautolock.h"
28 #include "mapsector.h"
29 #include "mapblock_mesh.h"
34 #include "nodemetadata.h"
37 #include <IFileSystem.h>
43 QueuedMeshUpdate::QueuedMeshUpdate():
46 ack_block_to_server(false)
50 QueuedMeshUpdate::~QueuedMeshUpdate()
60 MeshUpdateQueue::MeshUpdateQueue()
65 MeshUpdateQueue::~MeshUpdateQueue()
67 JMutexAutoLock lock(m_mutex);
69 core::list<QueuedMeshUpdate*>::Iterator i;
70 for(i=m_queue.begin(); i!=m_queue.end(); i++)
72 QueuedMeshUpdate *q = *i;
78 peer_id=0 adds with nobody to send to
80 void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server)
82 DSTACK(__FUNCTION_NAME);
86 JMutexAutoLock lock(m_mutex);
89 Find if block is already in queue.
90 If it is, update the data and quit.
92 core::list<QueuedMeshUpdate*>::Iterator i;
93 for(i=m_queue.begin(); i!=m_queue.end(); i++)
95 QueuedMeshUpdate *q = *i;
101 if(ack_block_to_server)
102 q->ack_block_to_server = true;
110 QueuedMeshUpdate *q = new QueuedMeshUpdate;
113 q->ack_block_to_server = ack_block_to_server;
114 m_queue.push_back(q);
117 // Returned pointer must be deleted
118 // Returns NULL if queue is empty
119 QueuedMeshUpdate * MeshUpdateQueue::pop()
121 JMutexAutoLock lock(m_mutex);
123 core::list<QueuedMeshUpdate*>::Iterator i = m_queue.begin();
124 if(i == m_queue.end())
126 QueuedMeshUpdate *q = *i;
135 void * MeshUpdateThread::Thread()
139 log_register_thread("MeshUpdateThread");
141 DSTACK(__FUNCTION_NAME);
143 BEGIN_DEBUG_EXCEPTION_HANDLER
147 /*// Wait for output queue to flush.
148 // Allow 2 in queue, this makes less frametime jitter.
149 // Umm actually, there is no much difference
150 if(m_queue_out.size() >= 2)
156 QueuedMeshUpdate *q = m_queue_in.pop();
163 ScopeProfiler sp(g_profiler, "Client: Mesh making");
165 scene::SMesh *mesh_new = NULL;
166 mesh_new = makeMapBlockMesh(q->data, m_gamedef);
171 r.ack_block_to_server = q->ack_block_to_server;
173 /*infostream<<"MeshUpdateThread: Processed "
174 <<"("<<q->p.X<<","<<q->p.Y<<","<<q->p.Z<<")"
177 m_queue_out.push_back(r);
182 END_DEBUG_EXCEPTION_HANDLER(errorstream)
188 IrrlichtDevice *device,
189 const char *playername,
190 std::string password,
191 MapDrawControl &control,
192 IWritableTextureSource *tsrc,
193 IWritableToolDefManager *tooldef,
194 IWritableNodeDefManager *nodedef
199 m_mesh_update_thread(this),
201 new ClientMap(this, this, control,
202 device->getSceneManager()->getRootSceneNode(),
203 device->getSceneManager(), 666),
204 device->getSceneManager(),
207 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
209 m_server_ser_ver(SER_FMT_VER_INVALID),
210 m_inventory_updated(false),
213 m_password(password),
214 m_access_denied(false),
215 m_texture_receive_progress(0),
216 m_textures_received(false),
217 m_tooldef_received(false),
218 m_nodedef_received(false)
220 m_packetcounter_timer = 0.0;
221 //m_delete_unused_sectors_timer = 0.0;
222 m_connection_reinit_timer = 0.0;
223 m_avg_rtt_timer = 0.0;
224 m_playerpos_send_timer = 0.0;
225 m_ignore_damage_timer = 0.0;
227 // Build main texture atlas, now that the GameDef exists (that is, us)
228 if(g_settings->getBool("enable_texture_atlas"))
229 m_tsrc->buildMainAtlas(this);
231 infostream<<"Not building texture atlas."<<std::endl;
233 // Update node textures
234 m_nodedef->updateTextures(m_tsrc);
236 // Start threads after setting up content definitions
237 m_mesh_update_thread.Start();
243 Player *player = new LocalPlayer(this);
245 player->updateName(playername);
247 m_env.addPlayer(player);
249 // Initialize player in the inventory context
250 m_inventory_context.current_player = player;
257 //JMutexAutoLock conlock(m_con_mutex); //bulk comment-out
261 m_mesh_update_thread.setRun(false);
262 while(m_mesh_update_thread.IsRunning())
266 void Client::connect(Address address)
268 DSTACK(__FUNCTION_NAME);
269 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
270 m_con.SetTimeoutMs(0);
271 m_con.Connect(address);
274 bool Client::connectedAndInitialized()
276 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
278 if(m_con.Connected() == false)
281 if(m_server_ser_ver == SER_FMT_VER_INVALID)
287 void Client::step(float dtime)
289 DSTACK(__FUNCTION_NAME);
295 if(m_ignore_damage_timer > dtime)
296 m_ignore_damage_timer -= dtime;
298 m_ignore_damage_timer = 0.0;
300 //infostream<<"Client steps "<<dtime<<std::endl;
303 //TimeTaker timer("ReceiveAll()", m_device);
309 //TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device);
311 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
312 m_con.RunTimeouts(dtime);
319 float &counter = m_packetcounter_timer;
325 infostream<<"Client packetcounter (20s):"<<std::endl;
326 m_packetcounter.print(infostream);
327 m_packetcounter.clear();
331 // Get connection status
332 bool connected = connectedAndInitialized();
337 Delete unused sectors
339 NOTE: This jams the game for a while because deleting sectors
343 float &counter = m_delete_unused_sectors_timer;
351 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
353 core::list<v3s16> deleted_blocks;
355 float delete_unused_sectors_timeout =
356 g_settings->getFloat("client_delete_unused_sectors_timeout");
358 // Delete sector blocks
359 /*u32 num = m_env.getMap().unloadUnusedData
360 (delete_unused_sectors_timeout,
361 true, &deleted_blocks);*/
363 // Delete whole sectors
364 m_env.getMap().unloadUnusedData
365 (delete_unused_sectors_timeout,
368 if(deleted_blocks.size() > 0)
370 /*infostream<<"Client: Deleted blocks of "<<num
371 <<" unused sectors"<<std::endl;*/
372 /*infostream<<"Client: Deleted "<<num
373 <<" unused sectors"<<std::endl;*/
379 // Env is locked so con can be locked.
380 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
382 core::list<v3s16>::Iterator i = deleted_blocks.begin();
383 core::list<v3s16> sendlist;
386 if(sendlist.size() == 255 || i == deleted_blocks.end())
388 if(sendlist.size() == 0)
397 u32 replysize = 2+1+6*sendlist.size();
398 SharedBuffer<u8> reply(replysize);
399 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
400 reply[2] = sendlist.size();
402 for(core::list<v3s16>::Iterator
403 j = sendlist.begin();
404 j != sendlist.end(); j++)
406 writeV3S16(&reply[2+1+6*k], *j);
409 m_con.Send(PEER_ID_SERVER, 1, reply, true);
411 if(i == deleted_blocks.end())
417 sendlist.push_back(*i);
425 if(connected == false)
427 float &counter = m_connection_reinit_timer;
433 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
435 Player *myplayer = m_env.getLocalPlayer();
436 assert(myplayer != NULL);
438 // Send TOSERVER_INIT
439 // [0] u16 TOSERVER_INIT
440 // [2] u8 SER_FMT_VER_HIGHEST
441 // [3] u8[20] player_name
442 // [23] u8[28] password (new in some version)
443 // [51] u16 client network protocol version (new in some version)
444 SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2);
445 writeU16(&data[0], TOSERVER_INIT);
446 writeU8(&data[2], SER_FMT_VER_HIGHEST);
448 memset((char*)&data[3], 0, PLAYERNAME_SIZE);
449 snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
451 /*infostream<<"Client: sending initial password hash: \""<<m_password<<"\""
454 memset((char*)&data[23], 0, PASSWORD_SIZE);
455 snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
457 // This should be incremented in each version
458 writeU16(&data[51], PROTOCOL_VERSION);
460 // Send as unreliable
461 Send(0, data, false);
464 // Not connected, return
469 Do stuff if connected
473 Run Map's timers and unload unused data
475 const float map_timer_and_unload_dtime = 5.25;
476 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
478 ScopeProfiler sp(g_profiler, "Client: map timer and unload");
479 core::list<v3s16> deleted_blocks;
480 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
481 g_settings->getFloat("client_unload_unused_data_timeout"),
484 /*if(deleted_blocks.size() > 0)
485 infostream<<"Client: Unloaded "<<deleted_blocks.size()
486 <<" unused blocks"<<std::endl;*/
490 NOTE: This loop is intentionally iterated the way it is.
493 core::list<v3s16>::Iterator i = deleted_blocks.begin();
494 core::list<v3s16> sendlist;
497 if(sendlist.size() == 255 || i == deleted_blocks.end())
499 if(sendlist.size() == 0)
508 u32 replysize = 2+1+6*sendlist.size();
509 SharedBuffer<u8> reply(replysize);
510 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
511 reply[2] = sendlist.size();
513 for(core::list<v3s16>::Iterator
514 j = sendlist.begin();
515 j != sendlist.end(); j++)
517 writeV3S16(&reply[2+1+6*k], *j);
520 m_con.Send(PEER_ID_SERVER, 1, reply, true);
522 if(i == deleted_blocks.end())
528 sendlist.push_back(*i);
538 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
540 // Control local player (0ms)
541 LocalPlayer *player = m_env.getLocalPlayer();
542 assert(player != NULL);
543 player->applyControl(dtime);
545 //TimeTaker envtimer("env step", m_device);
554 ClientEnvEvent event = m_env.getClientEvent();
555 if(event.type == CEE_NONE)
559 else if(event.type == CEE_PLAYER_DAMAGE)
561 if(m_ignore_damage_timer <= 0)
563 u8 damage = event.player_damage.amount;
566 // Add to ClientEvent queue
568 event.type = CE_PLAYER_DAMAGE;
569 event.player_damage.amount = damage;
570 m_client_event_queue.push_back(event);
580 float &counter = m_avg_rtt_timer;
585 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
586 // connectedAndInitialized() is true, peer exists.
587 float avg_rtt = m_con.GetPeerAvgRTT(PEER_ID_SERVER);
588 infostream<<"Client: avg_rtt="<<avg_rtt<<std::endl;
593 Send player position to server
596 float &counter = m_playerpos_send_timer;
606 Replace updated meshes
609 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
611 //TimeTaker timer("** Processing mesh update result queue");
614 /*infostream<<"Mesh update result queue size is "
615 <<m_mesh_update_thread.m_queue_out.size()
618 while(m_mesh_update_thread.m_queue_out.size() > 0)
620 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
621 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
624 block->replaceMesh(r.mesh);
626 if(r.ack_block_to_server)
628 /*infostream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
629 <<","<<r.p.Z<<")"<<std::endl;*/
640 u32 replysize = 2+1+6;
641 SharedBuffer<u8> reply(replysize);
642 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
644 writeV3S16(&reply[3], r.p);
646 m_con.Send(PEER_ID_SERVER, 1, reply, true);
652 // Virtual methods from con::PeerHandler
653 void Client::peerAdded(con::Peer *peer)
655 infostream<<"Client::peerAdded(): peer->id="
656 <<peer->id<<std::endl;
658 void Client::deletingPeer(con::Peer *peer, bool timeout)
660 infostream<<"Client::deletingPeer(): "
661 "Server Peer is getting deleted "
662 <<"(timeout="<<timeout<<")"<<std::endl;
665 void Client::ReceiveAll()
667 DSTACK(__FUNCTION_NAME);
668 u32 start_ms = porting::getTimeMs();
671 // Limit time even if there would be huge amounts of data to
673 if(porting::getTimeMs() > start_ms + 100)
679 catch(con::NoIncomingDataException &e)
683 catch(con::InvalidIncomingDataException &e)
685 infostream<<"Client::ReceiveAll(): "
686 "InvalidIncomingDataException: what()="
687 <<e.what()<<std::endl;
692 void Client::Receive()
694 DSTACK(__FUNCTION_NAME);
695 SharedBuffer<u8> data;
699 //TimeTaker t1("con mutex and receive", m_device);
700 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
701 datasize = m_con.Receive(sender_peer_id, data);
703 //TimeTaker t1("ProcessData", m_device);
704 ProcessData(*data, datasize, sender_peer_id);
708 sender_peer_id given to this shall be quaranteed to be a valid peer
710 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
712 DSTACK(__FUNCTION_NAME);
714 // Ignore packets that don't even fit a command
717 m_packetcounter.add(60000);
721 ToClientCommand command = (ToClientCommand)readU16(&data[0]);
723 //infostream<<"Client: received command="<<command<<std::endl;
724 m_packetcounter.add((u16)command);
727 If this check is removed, be sure to change the queue
728 system to know the ids
730 if(sender_peer_id != PEER_ID_SERVER)
732 infostream<<"Client::ProcessData(): Discarding data not "
733 "coming from server: peer_id="<<sender_peer_id
738 u8 ser_version = m_server_ser_ver;
740 //infostream<<"Client received command="<<(int)command<<std::endl;
742 if(command == TOCLIENT_INIT)
747 u8 deployed = data[2];
749 infostream<<"Client: TOCLIENT_INIT received with "
750 "deployed="<<((int)deployed&0xff)<<std::endl;
752 if(deployed < SER_FMT_VER_LOWEST
753 || deployed > SER_FMT_VER_HIGHEST)
755 infostream<<"Client: TOCLIENT_INIT: Server sent "
756 <<"unsupported ser_fmt_ver"<<std::endl;
760 m_server_ser_ver = deployed;
762 // Get player position
763 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
764 if(datasize >= 2+1+6)
765 playerpos_s16 = readV3S16(&data[2+1]);
766 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
769 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
771 // Set player position
772 Player *player = m_env.getLocalPlayer();
773 assert(player != NULL);
774 player->setPosition(playerpos_f);
777 if(datasize >= 2+1+6+8)
780 m_map_seed = readU64(&data[2+1+6]);
781 infostream<<"Client: received map seed: "<<m_map_seed<<std::endl;
786 SharedBuffer<u8> reply(replysize);
787 writeU16(&reply[0], TOSERVER_INIT2);
789 m_con.Send(PEER_ID_SERVER, 1, reply, true);
794 if(command == TOCLIENT_ACCESS_DENIED)
796 // The server didn't like our password. Note, this needs
797 // to be processed even if the serialisation format has
798 // not been agreed yet, the same as TOCLIENT_INIT.
799 m_access_denied = true;
800 m_access_denied_reason = L"Unknown";
803 std::string datastring((char*)&data[2], datasize-2);
804 std::istringstream is(datastring, std::ios_base::binary);
805 m_access_denied_reason = deSerializeWideString(is);
810 if(ser_version == SER_FMT_VER_INVALID)
812 infostream<<"Client: Server serialization"
813 " format invalid or not initialized."
814 " Skipping incoming command="<<command<<std::endl;
818 // Just here to avoid putting the two if's together when
819 // making some copypasta
822 if(command == TOCLIENT_REMOVENODE)
827 p.X = readS16(&data[2]);
828 p.Y = readS16(&data[4]);
829 p.Z = readS16(&data[6]);
831 //TimeTaker t1("TOCLIENT_REMOVENODE");
833 // This will clear the cracking animation after digging
834 ((ClientMap&)m_env.getMap()).clearTempMod(p);
838 else if(command == TOCLIENT_ADDNODE)
840 if(datasize < 8 + MapNode::serializedLength(ser_version))
844 p.X = readS16(&data[2]);
845 p.Y = readS16(&data[4]);
846 p.Z = readS16(&data[6]);
848 //TimeTaker t1("TOCLIENT_ADDNODE");
851 n.deSerialize(&data[8], ser_version);
855 else if(command == TOCLIENT_BLOCKDATA)
857 // Ignore too small packet
862 p.X = readS16(&data[2]);
863 p.Y = readS16(&data[4]);
864 p.Z = readS16(&data[6]);
866 /*infostream<<"Client: Thread: BLOCKDATA for ("
867 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
868 /*infostream<<"Client: Thread: BLOCKDATA for ("
869 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
871 std::string datastring((char*)&data[8], datasize-8);
872 std::istringstream istr(datastring, std::ios_base::binary);
878 sector = m_env.getMap().emergeSector(p2d);
880 assert(sector->getPos() == p2d);
882 //TimeTaker timer("MapBlock deSerialize");
885 block = sector->getBlockNoCreateNoEx(p.Y);
889 Update an existing block
891 //infostream<<"Updating"<<std::endl;
892 block->deSerialize(istr, ser_version);
899 //infostream<<"Creating new"<<std::endl;
900 block = new MapBlock(&m_env.getMap(), p, this);
901 block->deSerialize(istr, ser_version);
902 sector->insertBlock(block);
916 u32 replysize = 2+1+6;
917 SharedBuffer<u8> reply(replysize);
918 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
920 writeV3S16(&reply[3], p);
922 m_con.Send(PEER_ID_SERVER, 1, reply, true);
926 Update Mesh of this block and blocks at x-, y- and z-.
927 Environment should not be locked as it interlocks with the
928 main thread, from which is will want to retrieve textures.
931 //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
933 Add it to mesh update queue and set it to be acknowledged after update.
935 //infostream<<"Adding mesh update task for received block"<<std::endl;
936 addUpdateMeshTaskWithEdge(p, true);
938 else if(command == TOCLIENT_PLAYERPOS)
940 infostream<<"Received deprecated TOCLIENT_PLAYERPOS"
944 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
945 our_peer_id = m_con.GetPeerID();
947 // Cancel if we don't have a peer id
948 if(our_peer_id == PEER_ID_INEXISTENT){
949 infostream<<"TOCLIENT_PLAYERPOS cancelled: "
956 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
958 u32 player_size = 2+12+12+4+4;
960 u32 player_count = (datasize-2) / player_size;
962 for(u32 i=0; i<player_count; i++)
964 u16 peer_id = readU16(&data[start]);
966 Player *player = m_env.getPlayer(peer_id);
968 // Skip if player doesn't exist
971 start += player_size;
975 // Skip if player is local player
976 if(player->isLocal())
978 start += player_size;
982 v3s32 ps = readV3S32(&data[start+2]);
983 v3s32 ss = readV3S32(&data[start+2+12]);
984 s32 pitch_i = readS32(&data[start+2+12+12]);
985 s32 yaw_i = readS32(&data[start+2+12+12+4]);
986 /*infostream<<"Client: got "
987 <<"pitch_i="<<pitch_i
988 <<" yaw_i="<<yaw_i<<std::endl;*/
989 f32 pitch = (f32)pitch_i / 100.0;
990 f32 yaw = (f32)yaw_i / 100.0;
991 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
992 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
993 player->setPosition(position);
994 player->setSpeed(speed);
995 player->setPitch(pitch);
998 /*infostream<<"Client: player "<<peer_id
1000 <<" yaw="<<yaw<<std::endl;*/
1002 start += player_size;
1006 else if(command == TOCLIENT_PLAYERINFO)
1010 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1011 our_peer_id = m_con.GetPeerID();
1013 // Cancel if we don't have a peer id
1014 if(our_peer_id == PEER_ID_INEXISTENT){
1015 infostream<<"TOCLIENT_PLAYERINFO cancelled: "
1016 "we have no peer id"
1021 //infostream<<"Client: Server reports players:"<<std::endl;
1024 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1026 u32 item_size = 2+PLAYERNAME_SIZE;
1027 u32 player_count = (datasize-2) / item_size;
1030 core::list<u16> players_alive;
1031 for(u32 i=0; i<player_count; i++)
1033 // Make sure the name ends in '\0'
1034 data[start+2+20-1] = 0;
1036 u16 peer_id = readU16(&data[start]);
1038 players_alive.push_back(peer_id);
1040 /*infostream<<"peer_id="<<peer_id
1041 <<" name="<<((char*)&data[start+2])<<std::endl;*/
1043 // Don't update the info of the local player
1044 if(peer_id == our_peer_id)
1050 Player *player = m_env.getPlayer(peer_id);
1052 // Create a player if it doesn't exist
1055 player = new RemotePlayer(this,
1056 m_device->getSceneManager()->getRootSceneNode(),
1059 player->peer_id = peer_id;
1060 m_env.addPlayer(player);
1061 infostream<<"Client: Adding new player "
1062 <<peer_id<<std::endl;
1065 player->updateName((char*)&data[start+2]);
1071 Remove those players from the environment that
1072 weren't listed by the server.
1074 //infostream<<"Removing dead players"<<std::endl;
1075 core::list<Player*> players = m_env.getPlayers();
1076 core::list<Player*>::Iterator ip;
1077 for(ip=players.begin(); ip!=players.end(); ip++)
1079 // Ingore local player
1080 if((*ip)->isLocal())
1083 // Warn about a special case
1084 if((*ip)->peer_id == 0)
1086 infostream<<"Client: Removing "
1087 "dead player with id=0"<<std::endl;
1090 bool is_alive = false;
1091 core::list<u16>::Iterator i;
1092 for(i=players_alive.begin(); i!=players_alive.end(); i++)
1094 if((*ip)->peer_id == *i)
1100 /*infostream<<"peer_id="<<((*ip)->peer_id)
1101 <<" is_alive="<<is_alive<<std::endl;*/
1104 infostream<<"Removing dead player "<<(*ip)->peer_id
1106 m_env.removePlayer((*ip)->peer_id);
1110 else if(command == TOCLIENT_SECTORMETA)
1112 infostream<<"Client received DEPRECATED TOCLIENT_SECTORMETA"<<std::endl;
1117 [3...] v2s16 pos + sector metadata
1122 //infostream<<"Client received TOCLIENT_SECTORMETA"<<std::endl;
1125 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1127 std::string datastring((char*)&data[2], datasize-2);
1128 std::istringstream is(datastring, std::ios_base::binary);
1132 is.read((char*)buf, 1);
1133 u16 sector_count = readU8(buf);
1135 //infostream<<"sector_count="<<sector_count<<std::endl;
1137 for(u16 i=0; i<sector_count; i++)
1140 is.read((char*)buf, 4);
1141 v2s16 pos = readV2S16(buf);
1142 /*infostream<<"Client: deserializing sector at "
1143 <<"("<<pos.X<<","<<pos.Y<<")"<<std::endl;*/
1145 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
1146 ((ClientMap&)m_env.getMap()).deSerializeSector(pos, is);
1151 else if(command == TOCLIENT_INVENTORY)
1156 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
1159 //TimeTaker t2("mutex locking", m_device);
1160 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1163 //TimeTaker t3("istringstream init", m_device);
1164 std::string datastring((char*)&data[2], datasize-2);
1165 std::istringstream is(datastring, std::ios_base::binary);
1168 //m_env.printPlayers(infostream);
1170 //TimeTaker t4("player get", m_device);
1171 Player *player = m_env.getLocalPlayer();
1172 assert(player != NULL);
1175 //TimeTaker t1("inventory.deSerialize()", m_device);
1176 player->inventory.deSerialize(is, this);
1179 m_inventory_updated = true;
1181 //infostream<<"Client got player inventory:"<<std::endl;
1182 //player->inventory.print(infostream);
1186 else if(command == TOCLIENT_OBJECTDATA)
1188 // Strip command word and create a stringstream
1189 std::string datastring((char*)&data[2], datasize-2);
1190 std::istringstream is(datastring, std::ios_base::binary);
1198 is.read((char*)buf, 2);
1199 u16 playercount = readU16(buf);
1201 for(u16 i=0; i<playercount; i++)
1203 is.read((char*)buf, 2);
1204 u16 peer_id = readU16(buf);
1205 is.read((char*)buf, 12);
1206 v3s32 p_i = readV3S32(buf);
1207 is.read((char*)buf, 12);
1208 v3s32 s_i = readV3S32(buf);
1209 is.read((char*)buf, 4);
1210 s32 pitch_i = readS32(buf);
1211 is.read((char*)buf, 4);
1212 s32 yaw_i = readS32(buf);
1214 Player *player = m_env.getPlayer(peer_id);
1216 // Skip if player doesn't exist
1222 // Skip if player is local player
1223 if(player->isLocal())
1228 f32 pitch = (f32)pitch_i / 100.0;
1229 f32 yaw = (f32)yaw_i / 100.0;
1230 v3f position((f32)p_i.X/100., (f32)p_i.Y/100., (f32)p_i.Z/100.);
1231 v3f speed((f32)s_i.X/100., (f32)s_i.Y/100., (f32)s_i.Z/100.);
1233 player->setPosition(position);
1234 player->setSpeed(speed);
1235 player->setPitch(pitch);
1236 player->setYaw(yaw);
1241 NOTE: Deprecated stuff
1244 // Read active block count
1245 u16 blockcount = readU16(is);
1246 if(blockcount != 0){
1247 infostream<<"TOCLIENT_OBJECTDATA: blockcount != 0 "
1248 "not supported"<<std::endl;
1252 else if(command == TOCLIENT_TIME_OF_DAY)
1257 u16 time_of_day = readU16(&data[2]);
1258 time_of_day = time_of_day % 24000;
1259 //infostream<<"Client: time_of_day="<<time_of_day<<std::endl;
1267 m_env.setTimeOfDay(time_of_day);
1269 u32 dr = m_env.getDayNightRatio();
1271 infostream<<"Client: time_of_day="<<time_of_day
1277 else if(command == TOCLIENT_CHAT_MESSAGE)
1285 std::string datastring((char*)&data[2], datasize-2);
1286 std::istringstream is(datastring, std::ios_base::binary);
1289 is.read((char*)buf, 2);
1290 u16 len = readU16(buf);
1292 std::wstring message;
1293 for(u16 i=0; i<len; i++)
1295 is.read((char*)buf, 2);
1296 message += (wchar_t)readU16(buf);
1299 /*infostream<<"Client received chat message: "
1300 <<wide_to_narrow(message)<<std::endl;*/
1302 m_chat_queue.push_back(message);
1304 else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1306 //if(g_settings->getBool("enable_experimental"))
1310 u16 count of removed objects
1311 for all removed objects {
1314 u16 count of added objects
1315 for all added objects {
1318 u32 initialization data length
1319 string initialization data
1324 // Get all data except the command number
1325 std::string datastring((char*)&data[2], datasize-2);
1326 // Throw them in an istringstream
1327 std::istringstream is(datastring, std::ios_base::binary);
1331 // Read removed objects
1333 u16 removed_count = readU16((u8*)buf);
1334 for(u16 i=0; i<removed_count; i++)
1337 u16 id = readU16((u8*)buf);
1340 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1341 m_env.removeActiveObject(id);
1345 // Read added objects
1347 u16 added_count = readU16((u8*)buf);
1348 for(u16 i=0; i<added_count; i++)
1351 u16 id = readU16((u8*)buf);
1353 u8 type = readU8((u8*)buf);
1354 std::string data = deSerializeLongString(is);
1357 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1358 m_env.addActiveObject(id, type, data);
1363 else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1365 //if(g_settings->getBool("enable_experimental"))
1377 // Get all data except the command number
1378 std::string datastring((char*)&data[2], datasize-2);
1379 // Throw them in an istringstream
1380 std::istringstream is(datastring, std::ios_base::binary);
1382 while(is.eof() == false)
1386 u16 id = readU16((u8*)buf);
1390 u16 message_size = readU16((u8*)buf);
1391 std::string message;
1392 message.reserve(message_size);
1393 for(u16 i=0; i<message_size; i++)
1396 message.append(buf, 1);
1398 // Pass on to the environment
1400 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1401 m_env.processActiveObjectMessage(id, message);
1406 else if(command == TOCLIENT_HP)
1408 std::string datastring((char*)&data[2], datasize-2);
1409 std::istringstream is(datastring, std::ios_base::binary);
1410 Player *player = m_env.getLocalPlayer();
1411 assert(player != NULL);
1415 else if(command == TOCLIENT_MOVE_PLAYER)
1417 std::string datastring((char*)&data[2], datasize-2);
1418 std::istringstream is(datastring, std::ios_base::binary);
1419 Player *player = m_env.getLocalPlayer();
1420 assert(player != NULL);
1421 v3f pos = readV3F1000(is);
1422 f32 pitch = readF1000(is);
1423 f32 yaw = readF1000(is);
1424 player->setPosition(pos);
1425 /*player->setPitch(pitch);
1426 player->setYaw(yaw);*/
1428 infostream<<"Client got TOCLIENT_MOVE_PLAYER"
1429 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1435 Add to ClientEvent queue.
1436 This has to be sent to the main program because otherwise
1437 it would just force the pitch and yaw values to whatever
1438 the camera points to.
1441 event.type = CE_PLAYER_FORCE_MOVE;
1442 event.player_force_move.pitch = pitch;
1443 event.player_force_move.yaw = yaw;
1444 m_client_event_queue.push_back(event);
1446 // Ignore damage for a few seconds, so that the player doesn't
1447 // get damage from falling on ground
1448 m_ignore_damage_timer = 3.0;
1450 else if(command == TOCLIENT_PLAYERITEM)
1452 std::string datastring((char*)&data[2], datasize-2);
1453 std::istringstream is(datastring, std::ios_base::binary);
1455 u16 count = readU16(is);
1457 for (u16 i = 0; i < count; ++i) {
1458 u16 peer_id = readU16(is);
1459 Player *player = m_env.getPlayer(peer_id);
1463 infostream<<"Client: ignoring player item "
1464 << deSerializeString(is)
1465 << " for non-existing peer id " << peer_id
1468 } else if (player->isLocal()) {
1469 infostream<<"Client: ignoring player item "
1470 << deSerializeString(is)
1471 << " for local player" << std::endl;
1474 InventoryList *inv = player->inventory.getList("main");
1475 std::string itemstring(deSerializeString(is));
1476 if (itemstring.empty()) {
1479 <<"Client: empty player item for peer "
1480 << peer_id << std::endl;
1482 std::istringstream iss(itemstring);
1483 delete inv->changeItem(0,
1484 InventoryItem::deSerialize(iss, this));
1485 infostream<<"Client: player item for peer " << peer_id << ": ";
1486 player->getWieldItem()->serialize(infostream);
1487 infostream<<std::endl;
1492 else if(command == TOCLIENT_DEATHSCREEN)
1494 std::string datastring((char*)&data[2], datasize-2);
1495 std::istringstream is(datastring, std::ios_base::binary);
1497 bool set_camera_point_target = readU8(is);
1498 v3f camera_point_target = readV3F1000(is);
1501 event.type = CE_DEATHSCREEN;
1502 event.deathscreen.set_camera_point_target = set_camera_point_target;
1503 event.deathscreen.camera_point_target_x = camera_point_target.X;
1504 event.deathscreen.camera_point_target_y = camera_point_target.Y;
1505 event.deathscreen.camera_point_target_z = camera_point_target.Z;
1506 m_client_event_queue.push_back(event);
1508 else if(command == TOCLIENT_TEXTURES)
1510 io::IFileSystem *irrfs = m_device->getFileSystem();
1511 video::IVideoDriver *vdrv = m_device->getVideoDriver();
1513 std::string datastring((char*)&data[2], datasize-2);
1514 std::istringstream is(datastring, std::ios_base::binary);
1516 // Stop threads while updating content definitions
1517 m_mesh_update_thread.stop();
1521 u16 total number of texture bunches
1522 u16 index of this bunch
1523 u32 number of textures in this bunch
1531 int num_bunches = readU16(is);
1532 int bunch_i = readU16(is);
1533 m_texture_receive_progress = (float)bunch_i / (float)(num_bunches - 1);
1534 if(bunch_i == num_bunches - 1)
1535 m_textures_received = true;
1536 int num_textures = readU32(is);
1537 infostream<<"Client: Received textures: bunch "<<bunch_i<<"/"
1538 <<num_bunches<<" textures="<<num_textures
1539 <<" size="<<datasize<<std::endl;
1540 for(int i=0; i<num_textures; i++){
1541 std::string name = deSerializeString(is);
1542 std::string data = deSerializeLongString(is);
1543 // Silly irrlicht's const-incorrectness
1544 Buffer<char> data_rw(data.c_str(), data.size());
1545 // Create an irrlicht memory file
1546 io::IReadFile *rfile = irrfs->createMemoryReadFile(
1547 *data_rw, data.size(), "_tempreadfile");
1550 video::IImage *img = vdrv->createImageFromFile(rfile);
1552 errorstream<<"Client: Cannot create image from data of "
1553 <<"received texture \""<<name<<"\""<<std::endl;
1557 m_tsrc->insertSourceImage(name, img);
1562 if(m_nodedef_received && m_textures_received){
1563 // Rebuild inherited images and recreate textures
1564 m_tsrc->rebuildImagesAndTextures();
1566 // Update texture atlas
1567 if(g_settings->getBool("enable_texture_atlas"))
1568 m_tsrc->buildMainAtlas(this);
1570 // Update node textures
1571 m_nodedef->updateTextures(m_tsrc);
1575 m_mesh_update_thread.setRun(true);
1576 m_mesh_update_thread.Start();
1579 event.type = CE_TEXTURES_UPDATED;
1580 m_client_event_queue.push_back(event);
1582 else if(command == TOCLIENT_TOOLDEF)
1584 infostream<<"Client: Received tool definitions: packet size: "
1585 <<datasize<<std::endl;
1587 std::string datastring((char*)&data[2], datasize-2);
1588 std::istringstream is(datastring, std::ios_base::binary);
1590 m_tooldef_received = true;
1592 // Stop threads while updating content definitions
1593 m_mesh_update_thread.stop();
1595 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1596 m_tooldef->deSerialize(tmp_is);
1599 m_mesh_update_thread.setRun(true);
1600 m_mesh_update_thread.Start();
1602 else if(command == TOCLIENT_NODEDEF)
1604 infostream<<"Client: Received node definitions: packet size: "
1605 <<datasize<<std::endl;
1607 std::string datastring((char*)&data[2], datasize-2);
1608 std::istringstream is(datastring, std::ios_base::binary);
1610 m_nodedef_received = true;
1612 // Stop threads while updating content definitions
1613 m_mesh_update_thread.stop();
1615 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1616 m_nodedef->deSerialize(tmp_is, this);
1618 if(m_textures_received){
1619 // Update texture atlas
1620 if(g_settings->getBool("enable_texture_atlas"))
1621 m_tsrc->buildMainAtlas(this);
1623 // Update node textures
1624 m_nodedef->updateTextures(m_tsrc);
1628 m_mesh_update_thread.setRun(true);
1629 m_mesh_update_thread.Start();
1633 infostream<<"Client: Ignoring unknown command "
1634 <<command<<std::endl;
1638 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1640 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1641 m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1644 void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
1645 v3s16 nodepos_oversurface, u16 item)
1647 if(connectedAndInitialized() == false){
1648 infostream<<"Client::groundAction() "
1649 "cancelled (not connected)"
1658 [3] v3s16 nodepos_undersurface
1659 [9] v3s16 nodepos_abovesurface
1664 2: stop digging (all parameters ignored)
1665 3: digging completed
1667 u8 datasize = 2 + 1 + 6 + 6 + 2;
1668 SharedBuffer<u8> data(datasize);
1669 writeU16(&data[0], TOSERVER_GROUND_ACTION);
1670 writeU8(&data[2], action);
1671 writeV3S16(&data[3], nodepos_undersurface);
1672 writeV3S16(&data[9], nodepos_oversurface);
1673 writeU16(&data[15], item);
1674 Send(0, data, true);
1677 void Client::clickActiveObject(u8 button, u16 id, u16 item_i)
1679 if(connectedAndInitialized() == false){
1680 infostream<<"Client::clickActiveObject() "
1681 "cancelled (not connected)"
1686 Player *player = m_env.getLocalPlayer();
1690 ClientActiveObject *obj = m_env.getActiveObject(id);
1693 ToolItem *titem = NULL;
1694 std::string toolname = "";
1696 InventoryList *mlist = player->inventory.getList("main");
1699 InventoryItem *item = mlist->getItem(item_i);
1700 if(item && (std::string)item->getName() == "ToolItem")
1702 titem = (ToolItem*)item;
1703 toolname = titem->getToolName();
1707 v3f playerpos = player->getPosition();
1708 v3f objpos = obj->getPosition();
1709 v3f dir = (objpos - playerpos).normalize();
1711 bool disable_send = obj->directReportPunch(toolname, dir);
1721 [2] u8 button (0=left, 1=right)
1725 u8 datasize = 2 + 1 + 6 + 2 + 2;
1726 SharedBuffer<u8> data(datasize);
1727 writeU16(&data[0], TOSERVER_CLICK_ACTIVEOBJECT);
1728 writeU8(&data[2], button);
1729 writeU16(&data[3], id);
1730 writeU16(&data[5], item_i);
1731 Send(0, data, true);
1734 void Client::sendSignNodeText(v3s16 p, std::string text)
1742 std::ostringstream os(std::ios_base::binary);
1746 writeU16(buf, TOSERVER_SIGNNODETEXT);
1747 os.write((char*)buf, 2);
1751 os.write((char*)buf, 6);
1753 u16 textlen = text.size();
1754 // Write text length
1755 writeS16(buf, textlen);
1756 os.write((char*)buf, 2);
1759 os.write((char*)text.c_str(), textlen);
1762 std::string s = os.str();
1763 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1765 Send(0, data, true);
1768 void Client::sendInventoryAction(InventoryAction *a)
1770 std::ostringstream os(std::ios_base::binary);
1774 writeU16(buf, TOSERVER_INVENTORY_ACTION);
1775 os.write((char*)buf, 2);
1780 std::string s = os.str();
1781 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1783 Send(0, data, true);
1786 void Client::sendChatMessage(const std::wstring &message)
1788 std::ostringstream os(std::ios_base::binary);
1792 writeU16(buf, TOSERVER_CHAT_MESSAGE);
1793 os.write((char*)buf, 2);
1796 writeU16(buf, message.size());
1797 os.write((char*)buf, 2);
1800 for(u32 i=0; i<message.size(); i++)
1804 os.write((char*)buf, 2);
1808 std::string s = os.str();
1809 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1811 Send(0, data, true);
1814 void Client::sendChangePassword(const std::wstring oldpassword,
1815 const std::wstring newpassword)
1817 Player *player = m_env.getLocalPlayer();
1821 std::string playername = player->getName();
1822 std::string oldpwd = translatePassword(playername, oldpassword);
1823 std::string newpwd = translatePassword(playername, newpassword);
1825 std::ostringstream os(std::ios_base::binary);
1826 u8 buf[2+PASSWORD_SIZE*2];
1828 [0] u16 TOSERVER_PASSWORD
1829 [2] u8[28] old password
1830 [30] u8[28] new password
1833 writeU16(buf, TOSERVER_PASSWORD);
1834 for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1836 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1837 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1839 buf[2+PASSWORD_SIZE-1] = 0;
1840 buf[30+PASSWORD_SIZE-1] = 0;
1841 os.write((char*)buf, 2+PASSWORD_SIZE*2);
1844 std::string s = os.str();
1845 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1847 Send(0, data, true);
1851 void Client::sendDamage(u8 damage)
1853 DSTACK(__FUNCTION_NAME);
1854 std::ostringstream os(std::ios_base::binary);
1856 writeU16(os, TOSERVER_DAMAGE);
1857 writeU8(os, damage);
1860 std::string s = os.str();
1861 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1863 Send(0, data, true);
1866 void Client::sendRespawn()
1868 DSTACK(__FUNCTION_NAME);
1869 std::ostringstream os(std::ios_base::binary);
1871 writeU16(os, TOSERVER_RESPAWN);
1874 std::string s = os.str();
1875 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1877 Send(0, data, true);
1880 void Client::sendPlayerPos()
1882 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1884 Player *myplayer = m_env.getLocalPlayer();
1885 if(myplayer == NULL)
1890 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1891 our_peer_id = m_con.GetPeerID();
1894 // Set peer id if not set already
1895 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1896 myplayer->peer_id = our_peer_id;
1897 // Check that an existing peer_id is the same as the connection's
1898 assert(myplayer->peer_id == our_peer_id);
1900 v3f pf = myplayer->getPosition();
1901 v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1902 v3f sf = myplayer->getSpeed();
1903 v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1904 s32 pitch = myplayer->getPitch() * 100;
1905 s32 yaw = myplayer->getYaw() * 100;
1910 [2] v3s32 position*100
1911 [2+12] v3s32 speed*100
1912 [2+12+12] s32 pitch*100
1913 [2+12+12+4] s32 yaw*100
1916 SharedBuffer<u8> data(2+12+12+4+4);
1917 writeU16(&data[0], TOSERVER_PLAYERPOS);
1918 writeV3S32(&data[2], position);
1919 writeV3S32(&data[2+12], speed);
1920 writeS32(&data[2+12+12], pitch);
1921 writeS32(&data[2+12+12+4], yaw);
1923 // Send as unreliable
1924 Send(0, data, false);
1927 void Client::sendPlayerItem(u16 item)
1929 Player *myplayer = m_env.getLocalPlayer();
1930 if(myplayer == NULL)
1933 u16 our_peer_id = m_con.GetPeerID();
1935 // Set peer id if not set already
1936 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1937 myplayer->peer_id = our_peer_id;
1938 // Check that an existing peer_id is the same as the connection's
1939 assert(myplayer->peer_id == our_peer_id);
1941 SharedBuffer<u8> data(2+2);
1942 writeU16(&data[0], TOSERVER_PLAYERITEM);
1943 writeU16(&data[2], item);
1946 Send(0, data, true);
1949 void Client::removeNode(v3s16 p)
1951 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1953 core::map<v3s16, MapBlock*> modified_blocks;
1957 //TimeTaker t("removeNodeAndUpdate", m_device);
1958 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1960 catch(InvalidPositionException &e)
1964 for(core::map<v3s16, MapBlock * >::Iterator
1965 i = modified_blocks.getIterator();
1966 i.atEnd() == false; i++)
1968 v3s16 p = i.getNode()->getKey();
1969 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1970 addUpdateMeshTaskWithEdge(p);
1974 void Client::addNode(v3s16 p, MapNode n)
1976 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1978 TimeTaker timer1("Client::addNode()");
1980 core::map<v3s16, MapBlock*> modified_blocks;
1984 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1985 std::string st = std::string("");
1986 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st);
1988 catch(InvalidPositionException &e)
1991 //TimeTaker timer2("Client::addNode(): updateMeshes");
1993 for(core::map<v3s16, MapBlock * >::Iterator
1994 i = modified_blocks.getIterator();
1995 i.atEnd() == false; i++)
1997 v3s16 p = i.getNode()->getKey();
1998 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1999 addUpdateMeshTaskWithEdge(p);
2003 void Client::updateCamera(v3f pos, v3f dir, f32 fov)
2005 m_env.getClientMap().updateCamera(pos, dir, fov);
2008 void Client::renderPostFx()
2010 m_env.getClientMap().renderPostFx();
2013 MapNode Client::getNode(v3s16 p)
2015 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2016 return m_env.getMap().getNode(p);
2019 NodeMetadata* Client::getNodeMetadata(v3s16 p)
2021 return m_env.getMap().getNodeMetadata(p);
2024 LocalPlayer* Client::getLocalPlayer()
2026 return m_env.getLocalPlayer();
2029 void Client::setPlayerControl(PlayerControl &control)
2031 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2032 LocalPlayer *player = m_env.getLocalPlayer();
2033 assert(player != NULL);
2034 player->control = control;
2037 void Client::selectPlayerItem(u16 item)
2039 LocalPlayer *player = m_env.getLocalPlayer();
2040 assert(player != NULL);
2042 player->wieldItem(item);
2044 sendPlayerItem(item);
2047 // Returns true if the inventory of the local player has been
2048 // updated from the server. If it is true, it is set to false.
2049 bool Client::getLocalInventoryUpdated()
2051 // m_inventory_updated is behind envlock
2052 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2053 bool updated = m_inventory_updated;
2054 m_inventory_updated = false;
2058 // Copies the inventory of the local player to parameter
2059 void Client::getLocalInventory(Inventory &dst)
2061 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2062 Player *player = m_env.getLocalPlayer();
2063 assert(player != NULL);
2064 dst = player->inventory;
2067 InventoryContext *Client::getInventoryContext()
2069 return &m_inventory_context;
2072 Inventory* Client::getInventory(InventoryContext *c, std::string id)
2074 if(id == "current_player")
2076 assert(c->current_player);
2077 return &(c->current_player->inventory);
2081 std::string id0 = fn.next(":");
2083 if(id0 == "nodemeta")
2086 p.X = stoi(fn.next(","));
2087 p.Y = stoi(fn.next(","));
2088 p.Z = stoi(fn.next(","));
2089 NodeMetadata* meta = getNodeMetadata(p);
2091 return meta->getInventory();
2092 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
2093 <<"no metadata found"<<std::endl;
2097 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
2100 void Client::inventoryAction(InventoryAction *a)
2102 sendInventoryAction(a);
2105 ClientActiveObject * Client::getSelectedActiveObject(
2107 v3f from_pos_f_on_map,
2108 core::line3d<f32> shootline_on_map
2111 core::array<DistanceSortedActiveObject> objects;
2113 m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2115 //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2118 // After this, the closest object is the first in the array.
2121 for(u32 i=0; i<objects.size(); i++)
2123 ClientActiveObject *obj = objects[i].obj;
2125 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2126 if(selection_box == NULL)
2129 v3f pos = obj->getPosition();
2131 core::aabbox3d<f32> offsetted_box(
2132 selection_box->MinEdge + pos,
2133 selection_box->MaxEdge + pos
2136 if(offsetted_box.intersectsWithLine(shootline_on_map))
2138 //infostream<<"Returning selected object"<<std::endl;
2143 //infostream<<"No object selected; returning NULL."<<std::endl;
2147 void Client::printDebugInfo(std::ostream &os)
2149 //JMutexAutoLock lock1(m_fetchblock_mutex);
2150 /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2152 os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2153 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2154 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2158 u32 Client::getDayNightRatio()
2160 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2161 return m_env.getDayNightRatio();
2166 Player *player = m_env.getLocalPlayer();
2167 assert(player != NULL);
2171 void Client::setTempMod(v3s16 p, NodeMod mod)
2173 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2174 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2176 core::map<v3s16, MapBlock*> affected_blocks;
2177 ((ClientMap&)m_env.getMap()).setTempMod(p, mod,
2180 for(core::map<v3s16, MapBlock*>::Iterator
2181 i = affected_blocks.getIterator();
2182 i.atEnd() == false; i++)
2184 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2188 void Client::clearTempMod(v3s16 p)
2190 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2191 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2193 core::map<v3s16, MapBlock*> affected_blocks;
2194 ((ClientMap&)m_env.getMap()).clearTempMod(p,
2197 for(core::map<v3s16, MapBlock*>::Iterator
2198 i = affected_blocks.getIterator();
2199 i.atEnd() == false; i++)
2201 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2205 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
2207 /*infostream<<"Client::addUpdateMeshTask(): "
2208 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2211 MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2216 Create a task to update the mesh of the block
2219 MeshMakeData *data = new MeshMakeData;
2222 //TimeTaker timer("data fill");
2224 // Debug: 1-6ms, avg=2ms
2225 data->fill(getDayNightRatio(), b);
2229 //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2231 // Add task to queue
2232 m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server);
2234 /*infostream<<"Mesh update input queue size is "
2235 <<m_mesh_update_thread.m_queue_in.size()
2239 // Temporary test: make mesh directly in here
2241 //TimeTaker timer("make mesh");
2243 scene::SMesh *mesh_new = NULL;
2244 mesh_new = makeMapBlockMesh(data);
2245 b->replaceMesh(mesh_new);
2251 Mark mesh as non-expired at this point so that it can already
2252 be marked as expired again if the data changes
2254 b->setMeshExpired(false);
2257 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
2261 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2262 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2267 v3s16 p = blockpos + v3s16(0,0,0);
2268 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2269 addUpdateMeshTask(p, ack_to_server);
2271 catch(InvalidPositionException &e){}
2274 v3s16 p = blockpos + v3s16(-1,0,0);
2275 addUpdateMeshTask(p);
2277 catch(InvalidPositionException &e){}
2279 v3s16 p = blockpos + v3s16(0,-1,0);
2280 addUpdateMeshTask(p);
2282 catch(InvalidPositionException &e){}
2284 v3s16 p = blockpos + v3s16(0,0,-1);
2285 addUpdateMeshTask(p);
2287 catch(InvalidPositionException &e){}
2290 ClientEvent Client::getClientEvent()
2292 if(m_client_event_queue.size() == 0)
2295 event.type = CE_NONE;
2298 return m_client_event_queue.pop_front();
2301 float Client::getRTT(void)
2304 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2305 } catch(con::PeerNotFoundException &e){
2310 // IGameDef interface
2312 IToolDefManager* Client::getToolDefManager()
2316 INodeDefManager* Client::getNodeDefManager()
2320 ICraftDefManager* Client::getCraftDefManager()
2323 //return m_craftdef;
2325 ITextureSource* Client::getTextureSource()
2329 u16 Client::allocateUnknownNodeId(const std::string &name)
2331 errorstream<<"Client::allocateUnknownNodeId(): "
2332 <<"Client cannot allocate node IDs"<<std::endl;
2334 return CONTENT_IGNORE;