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)
216 m_packetcounter_timer = 0.0;
217 //m_delete_unused_sectors_timer = 0.0;
218 m_connection_reinit_timer = 0.0;
219 m_avg_rtt_timer = 0.0;
220 m_playerpos_send_timer = 0.0;
221 m_ignore_damage_timer = 0.0;
223 // Build main texture atlas, now that the GameDef exists (that is, us)
224 if(g_settings->getBool("enable_texture_atlas"))
225 m_tsrc->buildMainAtlas(this);
227 infostream<<"Not building texture atlas."<<std::endl;
229 // Update node textures
230 m_nodedef->updateTextures(m_tsrc);
232 // Start threads after setting up content definitions
233 m_mesh_update_thread.Start();
239 Player *player = new LocalPlayer(this);
241 player->updateName(playername);
243 m_env.addPlayer(player);
245 // Initialize player in the inventory context
246 m_inventory_context.current_player = player;
253 //JMutexAutoLock conlock(m_con_mutex); //bulk comment-out
257 m_mesh_update_thread.setRun(false);
258 while(m_mesh_update_thread.IsRunning())
262 void Client::connect(Address address)
264 DSTACK(__FUNCTION_NAME);
265 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
266 m_con.SetTimeoutMs(0);
267 m_con.Connect(address);
270 bool Client::connectedAndInitialized()
272 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
274 if(m_con.Connected() == false)
277 if(m_server_ser_ver == SER_FMT_VER_INVALID)
283 void Client::step(float dtime)
285 DSTACK(__FUNCTION_NAME);
291 if(m_ignore_damage_timer > dtime)
292 m_ignore_damage_timer -= dtime;
294 m_ignore_damage_timer = 0.0;
296 //infostream<<"Client steps "<<dtime<<std::endl;
299 //TimeTaker timer("ReceiveAll()", m_device);
305 //TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device);
307 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
308 m_con.RunTimeouts(dtime);
315 float &counter = m_packetcounter_timer;
321 infostream<<"Client packetcounter (20s):"<<std::endl;
322 m_packetcounter.print(infostream);
323 m_packetcounter.clear();
327 // Get connection status
328 bool connected = connectedAndInitialized();
333 Delete unused sectors
335 NOTE: This jams the game for a while because deleting sectors
339 float &counter = m_delete_unused_sectors_timer;
347 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
349 core::list<v3s16> deleted_blocks;
351 float delete_unused_sectors_timeout =
352 g_settings->getFloat("client_delete_unused_sectors_timeout");
354 // Delete sector blocks
355 /*u32 num = m_env.getMap().unloadUnusedData
356 (delete_unused_sectors_timeout,
357 true, &deleted_blocks);*/
359 // Delete whole sectors
360 m_env.getMap().unloadUnusedData
361 (delete_unused_sectors_timeout,
364 if(deleted_blocks.size() > 0)
366 /*infostream<<"Client: Deleted blocks of "<<num
367 <<" unused sectors"<<std::endl;*/
368 /*infostream<<"Client: Deleted "<<num
369 <<" unused sectors"<<std::endl;*/
375 // Env is locked so con can be locked.
376 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
378 core::list<v3s16>::Iterator i = deleted_blocks.begin();
379 core::list<v3s16> sendlist;
382 if(sendlist.size() == 255 || i == deleted_blocks.end())
384 if(sendlist.size() == 0)
393 u32 replysize = 2+1+6*sendlist.size();
394 SharedBuffer<u8> reply(replysize);
395 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
396 reply[2] = sendlist.size();
398 for(core::list<v3s16>::Iterator
399 j = sendlist.begin();
400 j != sendlist.end(); j++)
402 writeV3S16(&reply[2+1+6*k], *j);
405 m_con.Send(PEER_ID_SERVER, 1, reply, true);
407 if(i == deleted_blocks.end())
413 sendlist.push_back(*i);
421 if(connected == false)
423 float &counter = m_connection_reinit_timer;
429 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
431 Player *myplayer = m_env.getLocalPlayer();
432 assert(myplayer != NULL);
434 // Send TOSERVER_INIT
435 // [0] u16 TOSERVER_INIT
436 // [2] u8 SER_FMT_VER_HIGHEST
437 // [3] u8[20] player_name
438 // [23] u8[28] password (new in some version)
439 // [51] u16 client network protocol version (new in some version)
440 SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2);
441 writeU16(&data[0], TOSERVER_INIT);
442 writeU8(&data[2], SER_FMT_VER_HIGHEST);
444 memset((char*)&data[3], 0, PLAYERNAME_SIZE);
445 snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
447 /*infostream<<"Client: sending initial password hash: \""<<m_password<<"\""
450 memset((char*)&data[23], 0, PASSWORD_SIZE);
451 snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
453 // This should be incremented in each version
454 writeU16(&data[51], PROTOCOL_VERSION);
456 // Send as unreliable
457 Send(0, data, false);
460 // Not connected, return
465 Do stuff if connected
469 Run Map's timers and unload unused data
471 const float map_timer_and_unload_dtime = 5.25;
472 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
474 ScopeProfiler sp(g_profiler, "Client: map timer and unload");
475 core::list<v3s16> deleted_blocks;
476 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
477 g_settings->getFloat("client_unload_unused_data_timeout"),
480 /*if(deleted_blocks.size() > 0)
481 infostream<<"Client: Unloaded "<<deleted_blocks.size()
482 <<" unused blocks"<<std::endl;*/
486 NOTE: This loop is intentionally iterated the way it is.
489 core::list<v3s16>::Iterator i = deleted_blocks.begin();
490 core::list<v3s16> sendlist;
493 if(sendlist.size() == 255 || i == deleted_blocks.end())
495 if(sendlist.size() == 0)
504 u32 replysize = 2+1+6*sendlist.size();
505 SharedBuffer<u8> reply(replysize);
506 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
507 reply[2] = sendlist.size();
509 for(core::list<v3s16>::Iterator
510 j = sendlist.begin();
511 j != sendlist.end(); j++)
513 writeV3S16(&reply[2+1+6*k], *j);
516 m_con.Send(PEER_ID_SERVER, 1, reply, true);
518 if(i == deleted_blocks.end())
524 sendlist.push_back(*i);
534 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
536 // Control local player (0ms)
537 LocalPlayer *player = m_env.getLocalPlayer();
538 assert(player != NULL);
539 player->applyControl(dtime);
541 //TimeTaker envtimer("env step", m_device);
550 ClientEnvEvent event = m_env.getClientEvent();
551 if(event.type == CEE_NONE)
555 else if(event.type == CEE_PLAYER_DAMAGE)
557 if(m_ignore_damage_timer <= 0)
559 u8 damage = event.player_damage.amount;
562 // Add to ClientEvent queue
564 event.type = CE_PLAYER_DAMAGE;
565 event.player_damage.amount = damage;
566 m_client_event_queue.push_back(event);
576 float &counter = m_avg_rtt_timer;
581 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
582 // connectedAndInitialized() is true, peer exists.
583 float avg_rtt = m_con.GetPeerAvgRTT(PEER_ID_SERVER);
584 infostream<<"Client: avg_rtt="<<avg_rtt<<std::endl;
589 Send player position to server
592 float &counter = m_playerpos_send_timer;
602 Replace updated meshes
605 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
607 //TimeTaker timer("** Processing mesh update result queue");
610 /*infostream<<"Mesh update result queue size is "
611 <<m_mesh_update_thread.m_queue_out.size()
614 while(m_mesh_update_thread.m_queue_out.size() > 0)
616 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
617 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
620 block->replaceMesh(r.mesh);
622 if(r.ack_block_to_server)
624 /*infostream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
625 <<","<<r.p.Z<<")"<<std::endl;*/
636 u32 replysize = 2+1+6;
637 SharedBuffer<u8> reply(replysize);
638 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
640 writeV3S16(&reply[3], r.p);
642 m_con.Send(PEER_ID_SERVER, 1, reply, true);
648 // Virtual methods from con::PeerHandler
649 void Client::peerAdded(con::Peer *peer)
651 infostream<<"Client::peerAdded(): peer->id="
652 <<peer->id<<std::endl;
654 void Client::deletingPeer(con::Peer *peer, bool timeout)
656 infostream<<"Client::deletingPeer(): "
657 "Server Peer is getting deleted "
658 <<"(timeout="<<timeout<<")"<<std::endl;
661 void Client::ReceiveAll()
663 DSTACK(__FUNCTION_NAME);
669 catch(con::NoIncomingDataException &e)
673 catch(con::InvalidIncomingDataException &e)
675 infostream<<"Client::ReceiveAll(): "
676 "InvalidIncomingDataException: what()="
677 <<e.what()<<std::endl;
682 void Client::Receive()
684 DSTACK(__FUNCTION_NAME);
685 SharedBuffer<u8> data;
689 //TimeTaker t1("con mutex and receive", m_device);
690 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
691 datasize = m_con.Receive(sender_peer_id, data);
693 //TimeTaker t1("ProcessData", m_device);
694 ProcessData(*data, datasize, sender_peer_id);
698 sender_peer_id given to this shall be quaranteed to be a valid peer
700 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
702 DSTACK(__FUNCTION_NAME);
704 // Ignore packets that don't even fit a command
707 m_packetcounter.add(60000);
711 ToClientCommand command = (ToClientCommand)readU16(&data[0]);
713 //infostream<<"Client: received command="<<command<<std::endl;
714 m_packetcounter.add((u16)command);
717 If this check is removed, be sure to change the queue
718 system to know the ids
720 if(sender_peer_id != PEER_ID_SERVER)
722 infostream<<"Client::ProcessData(): Discarding data not "
723 "coming from server: peer_id="<<sender_peer_id
728 u8 ser_version = m_server_ser_ver;
730 //infostream<<"Client received command="<<(int)command<<std::endl;
732 if(command == TOCLIENT_INIT)
737 u8 deployed = data[2];
739 infostream<<"Client: TOCLIENT_INIT received with "
740 "deployed="<<((int)deployed&0xff)<<std::endl;
742 if(deployed < SER_FMT_VER_LOWEST
743 || deployed > SER_FMT_VER_HIGHEST)
745 infostream<<"Client: TOCLIENT_INIT: Server sent "
746 <<"unsupported ser_fmt_ver"<<std::endl;
750 m_server_ser_ver = deployed;
752 // Get player position
753 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
754 if(datasize >= 2+1+6)
755 playerpos_s16 = readV3S16(&data[2+1]);
756 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
759 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
761 // Set player position
762 Player *player = m_env.getLocalPlayer();
763 assert(player != NULL);
764 player->setPosition(playerpos_f);
767 if(datasize >= 2+1+6+8)
770 m_map_seed = readU64(&data[2+1+6]);
771 infostream<<"Client: received map seed: "<<m_map_seed<<std::endl;
776 SharedBuffer<u8> reply(replysize);
777 writeU16(&reply[0], TOSERVER_INIT2);
779 m_con.Send(PEER_ID_SERVER, 1, reply, true);
784 if(command == TOCLIENT_ACCESS_DENIED)
786 // The server didn't like our password. Note, this needs
787 // to be processed even if the serialisation format has
788 // not been agreed yet, the same as TOCLIENT_INIT.
789 m_access_denied = true;
790 m_access_denied_reason = L"Unknown";
793 std::string datastring((char*)&data[2], datasize-2);
794 std::istringstream is(datastring, std::ios_base::binary);
795 m_access_denied_reason = deSerializeWideString(is);
800 if(ser_version == SER_FMT_VER_INVALID)
802 infostream<<"Client: Server serialization"
803 " format invalid or not initialized."
804 " Skipping incoming command="<<command<<std::endl;
808 // Just here to avoid putting the two if's together when
809 // making some copypasta
812 if(command == TOCLIENT_REMOVENODE)
817 p.X = readS16(&data[2]);
818 p.Y = readS16(&data[4]);
819 p.Z = readS16(&data[6]);
821 //TimeTaker t1("TOCLIENT_REMOVENODE");
823 // This will clear the cracking animation after digging
824 ((ClientMap&)m_env.getMap()).clearTempMod(p);
828 else if(command == TOCLIENT_ADDNODE)
830 if(datasize < 8 + MapNode::serializedLength(ser_version))
834 p.X = readS16(&data[2]);
835 p.Y = readS16(&data[4]);
836 p.Z = readS16(&data[6]);
838 //TimeTaker t1("TOCLIENT_ADDNODE");
841 n.deSerialize(&data[8], ser_version, m_nodedef);
845 else if(command == TOCLIENT_BLOCKDATA)
847 // Ignore too small packet
852 p.X = readS16(&data[2]);
853 p.Y = readS16(&data[4]);
854 p.Z = readS16(&data[6]);
856 /*infostream<<"Client: Thread: BLOCKDATA for ("
857 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
858 /*infostream<<"Client: Thread: BLOCKDATA for ("
859 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
861 std::string datastring((char*)&data[8], datasize-8);
862 std::istringstream istr(datastring, std::ios_base::binary);
868 sector = m_env.getMap().emergeSector(p2d);
870 assert(sector->getPos() == p2d);
872 //TimeTaker timer("MapBlock deSerialize");
875 block = sector->getBlockNoCreateNoEx(p.Y);
879 Update an existing block
881 //infostream<<"Updating"<<std::endl;
882 block->deSerialize(istr, ser_version);
889 //infostream<<"Creating new"<<std::endl;
890 block = new MapBlock(&m_env.getMap(), p, this);
891 block->deSerialize(istr, ser_version);
892 sector->insertBlock(block);
896 mod.type = NODEMOD_CHANGECONTENT;
897 mod.param = CONTENT_MESE;
898 block->setTempMod(v3s16(8,10,8), mod);
899 block->setTempMod(v3s16(8,9,8), mod);
900 block->setTempMod(v3s16(8,8,8), mod);
901 block->setTempMod(v3s16(8,7,8), mod);
902 block->setTempMod(v3s16(8,6,8), mod);*/
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_TOOLDEF)
1510 infostream<<"Client: Received tool definitions: packet size: "
1511 <<datasize<<std::endl;
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();
1519 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1520 m_tooldef->deSerialize(tmp_is);
1523 m_mesh_update_thread.setRun(true);
1524 m_mesh_update_thread.Start();
1526 else if(command == TOCLIENT_TEXTURES)
1528 infostream<<"Client: Received textures: packet size: "<<datasize
1531 io::IFileSystem *irrfs = m_device->getFileSystem();
1532 video::IVideoDriver *vdrv = m_device->getVideoDriver();
1534 std::string datastring((char*)&data[2], datasize-2);
1535 std::istringstream is(datastring, std::ios_base::binary);
1537 // Stop threads while updating content definitions
1538 m_mesh_update_thread.stop();
1542 u32 number of textures
1550 int num_textures = readU32(is);
1551 infostream<<"Client: Received textures: count: "<<num_textures
1553 for(int i=0; i<num_textures; i++){
1554 std::string name = deSerializeString(is);
1555 std::string data = deSerializeLongString(is);
1556 // Silly irrlicht's const-incorrectness
1557 Buffer<char> data_rw(data.c_str(), data.size());
1558 // Create an irrlicht memory file
1559 io::IReadFile *rfile = irrfs->createMemoryReadFile(
1560 *data_rw, data.size(), "_tempreadfile");
1563 video::IImage *img = vdrv->createImageFromFile(rfile);
1565 errorstream<<"Client: Cannot create image from data of "
1566 <<"received texture \""<<name<<"\""<<std::endl;
1570 m_tsrc->insertSourceImage(name, img);
1575 // Rebuild inherited images and recreate textures
1576 m_tsrc->rebuildImagesAndTextures();
1578 // Update texture atlas
1579 if(g_settings->getBool("enable_texture_atlas"))
1580 m_tsrc->buildMainAtlas(this);
1582 // Update node textures
1583 m_nodedef->updateTextures(m_tsrc);
1586 m_mesh_update_thread.setRun(true);
1587 m_mesh_update_thread.Start();
1590 event.type = CE_TEXTURES_UPDATED;
1591 m_client_event_queue.push_back(event);
1593 else if(command == TOCLIENT_NODEDEF)
1595 infostream<<"Client: Received node definitions: packet size: "
1596 <<datasize<<std::endl;
1598 std::string datastring((char*)&data[2], datasize-2);
1599 std::istringstream is(datastring, std::ios_base::binary);
1601 // Stop threads while updating content definitions
1602 m_mesh_update_thread.stop();
1604 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1605 m_nodedef->deSerialize(tmp_is, this);
1607 // Update texture atlas
1608 if(g_settings->getBool("enable_texture_atlas"))
1609 m_tsrc->buildMainAtlas(this);
1611 // Update node textures
1612 m_nodedef->updateTextures(m_tsrc);
1615 m_mesh_update_thread.setRun(true);
1616 m_mesh_update_thread.Start();
1620 infostream<<"Client: Ignoring unknown command "
1621 <<command<<std::endl;
1625 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1627 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1628 m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1631 void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
1632 v3s16 nodepos_oversurface, u16 item)
1634 if(connectedAndInitialized() == false){
1635 infostream<<"Client::groundAction() "
1636 "cancelled (not connected)"
1645 [3] v3s16 nodepos_undersurface
1646 [9] v3s16 nodepos_abovesurface
1651 2: stop digging (all parameters ignored)
1652 3: digging completed
1654 u8 datasize = 2 + 1 + 6 + 6 + 2;
1655 SharedBuffer<u8> data(datasize);
1656 writeU16(&data[0], TOSERVER_GROUND_ACTION);
1657 writeU8(&data[2], action);
1658 writeV3S16(&data[3], nodepos_undersurface);
1659 writeV3S16(&data[9], nodepos_oversurface);
1660 writeU16(&data[15], item);
1661 Send(0, data, true);
1664 void Client::clickActiveObject(u8 button, u16 id, u16 item_i)
1666 if(connectedAndInitialized() == false){
1667 infostream<<"Client::clickActiveObject() "
1668 "cancelled (not connected)"
1673 Player *player = m_env.getLocalPlayer();
1677 ClientActiveObject *obj = m_env.getActiveObject(id);
1680 ToolItem *titem = NULL;
1681 std::string toolname = "";
1683 InventoryList *mlist = player->inventory.getList("main");
1686 InventoryItem *item = mlist->getItem(item_i);
1687 if(item && (std::string)item->getName() == "ToolItem")
1689 titem = (ToolItem*)item;
1690 toolname = titem->getToolName();
1694 v3f playerpos = player->getPosition();
1695 v3f objpos = obj->getPosition();
1696 v3f dir = (objpos - playerpos).normalize();
1698 bool disable_send = obj->directReportPunch(toolname, dir);
1708 [2] u8 button (0=left, 1=right)
1712 u8 datasize = 2 + 1 + 6 + 2 + 2;
1713 SharedBuffer<u8> data(datasize);
1714 writeU16(&data[0], TOSERVER_CLICK_ACTIVEOBJECT);
1715 writeU8(&data[2], button);
1716 writeU16(&data[3], id);
1717 writeU16(&data[5], item_i);
1718 Send(0, data, true);
1721 void Client::sendSignNodeText(v3s16 p, std::string text)
1729 std::ostringstream os(std::ios_base::binary);
1733 writeU16(buf, TOSERVER_SIGNNODETEXT);
1734 os.write((char*)buf, 2);
1738 os.write((char*)buf, 6);
1740 u16 textlen = text.size();
1741 // Write text length
1742 writeS16(buf, textlen);
1743 os.write((char*)buf, 2);
1746 os.write((char*)text.c_str(), textlen);
1749 std::string s = os.str();
1750 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1752 Send(0, data, true);
1755 void Client::sendInventoryAction(InventoryAction *a)
1757 std::ostringstream os(std::ios_base::binary);
1761 writeU16(buf, TOSERVER_INVENTORY_ACTION);
1762 os.write((char*)buf, 2);
1767 std::string s = os.str();
1768 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1770 Send(0, data, true);
1773 void Client::sendChatMessage(const std::wstring &message)
1775 std::ostringstream os(std::ios_base::binary);
1779 writeU16(buf, TOSERVER_CHAT_MESSAGE);
1780 os.write((char*)buf, 2);
1783 writeU16(buf, message.size());
1784 os.write((char*)buf, 2);
1787 for(u32 i=0; i<message.size(); i++)
1791 os.write((char*)buf, 2);
1795 std::string s = os.str();
1796 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1798 Send(0, data, true);
1801 void Client::sendChangePassword(const std::wstring oldpassword,
1802 const std::wstring newpassword)
1804 Player *player = m_env.getLocalPlayer();
1808 std::string playername = player->getName();
1809 std::string oldpwd = translatePassword(playername, oldpassword);
1810 std::string newpwd = translatePassword(playername, newpassword);
1812 std::ostringstream os(std::ios_base::binary);
1813 u8 buf[2+PASSWORD_SIZE*2];
1815 [0] u16 TOSERVER_PASSWORD
1816 [2] u8[28] old password
1817 [30] u8[28] new password
1820 writeU16(buf, TOSERVER_PASSWORD);
1821 for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1823 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1824 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1826 buf[2+PASSWORD_SIZE-1] = 0;
1827 buf[30+PASSWORD_SIZE-1] = 0;
1828 os.write((char*)buf, 2+PASSWORD_SIZE*2);
1831 std::string s = os.str();
1832 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1834 Send(0, data, true);
1838 void Client::sendDamage(u8 damage)
1840 DSTACK(__FUNCTION_NAME);
1841 std::ostringstream os(std::ios_base::binary);
1843 writeU16(os, TOSERVER_DAMAGE);
1844 writeU8(os, damage);
1847 std::string s = os.str();
1848 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1850 Send(0, data, true);
1853 void Client::sendRespawn()
1855 DSTACK(__FUNCTION_NAME);
1856 std::ostringstream os(std::ios_base::binary);
1858 writeU16(os, TOSERVER_RESPAWN);
1861 std::string s = os.str();
1862 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1864 Send(0, data, true);
1867 void Client::sendPlayerPos()
1869 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1871 Player *myplayer = m_env.getLocalPlayer();
1872 if(myplayer == NULL)
1877 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1878 our_peer_id = m_con.GetPeerID();
1881 // Set peer id if not set already
1882 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1883 myplayer->peer_id = our_peer_id;
1884 // Check that an existing peer_id is the same as the connection's
1885 assert(myplayer->peer_id == our_peer_id);
1887 v3f pf = myplayer->getPosition();
1888 v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1889 v3f sf = myplayer->getSpeed();
1890 v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1891 s32 pitch = myplayer->getPitch() * 100;
1892 s32 yaw = myplayer->getYaw() * 100;
1897 [2] v3s32 position*100
1898 [2+12] v3s32 speed*100
1899 [2+12+12] s32 pitch*100
1900 [2+12+12+4] s32 yaw*100
1903 SharedBuffer<u8> data(2+12+12+4+4);
1904 writeU16(&data[0], TOSERVER_PLAYERPOS);
1905 writeV3S32(&data[2], position);
1906 writeV3S32(&data[2+12], speed);
1907 writeS32(&data[2+12+12], pitch);
1908 writeS32(&data[2+12+12+4], yaw);
1910 // Send as unreliable
1911 Send(0, data, false);
1914 void Client::sendPlayerItem(u16 item)
1916 Player *myplayer = m_env.getLocalPlayer();
1917 if(myplayer == NULL)
1920 u16 our_peer_id = m_con.GetPeerID();
1922 // Set peer id if not set already
1923 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1924 myplayer->peer_id = our_peer_id;
1925 // Check that an existing peer_id is the same as the connection's
1926 assert(myplayer->peer_id == our_peer_id);
1928 SharedBuffer<u8> data(2+2);
1929 writeU16(&data[0], TOSERVER_PLAYERITEM);
1930 writeU16(&data[2], item);
1933 Send(0, data, true);
1936 void Client::removeNode(v3s16 p)
1938 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1940 core::map<v3s16, MapBlock*> modified_blocks;
1944 //TimeTaker t("removeNodeAndUpdate", m_device);
1945 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1947 catch(InvalidPositionException &e)
1951 for(core::map<v3s16, MapBlock * >::Iterator
1952 i = modified_blocks.getIterator();
1953 i.atEnd() == false; i++)
1955 v3s16 p = i.getNode()->getKey();
1956 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1957 addUpdateMeshTaskWithEdge(p);
1961 void Client::addNode(v3s16 p, MapNode n)
1963 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1965 TimeTaker timer1("Client::addNode()");
1967 core::map<v3s16, MapBlock*> modified_blocks;
1971 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1972 std::string st = std::string("");
1973 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st);
1975 catch(InvalidPositionException &e)
1978 //TimeTaker timer2("Client::addNode(): updateMeshes");
1980 for(core::map<v3s16, MapBlock * >::Iterator
1981 i = modified_blocks.getIterator();
1982 i.atEnd() == false; i++)
1984 v3s16 p = i.getNode()->getKey();
1985 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1986 addUpdateMeshTaskWithEdge(p);
1990 void Client::updateCamera(v3f pos, v3f dir, f32 fov)
1992 m_env.getClientMap().updateCamera(pos, dir, fov);
1995 void Client::renderPostFx()
1997 m_env.getClientMap().renderPostFx();
2000 MapNode Client::getNode(v3s16 p)
2002 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2003 return m_env.getMap().getNode(p);
2006 NodeMetadata* Client::getNodeMetadata(v3s16 p)
2008 return m_env.getMap().getNodeMetadata(p);
2011 LocalPlayer* Client::getLocalPlayer()
2013 return m_env.getLocalPlayer();
2016 void Client::setPlayerControl(PlayerControl &control)
2018 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2019 LocalPlayer *player = m_env.getLocalPlayer();
2020 assert(player != NULL);
2021 player->control = control;
2024 void Client::selectPlayerItem(u16 item)
2026 LocalPlayer *player = m_env.getLocalPlayer();
2027 assert(player != NULL);
2029 player->wieldItem(item);
2031 sendPlayerItem(item);
2034 // Returns true if the inventory of the local player has been
2035 // updated from the server. If it is true, it is set to false.
2036 bool Client::getLocalInventoryUpdated()
2038 // m_inventory_updated is behind envlock
2039 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2040 bool updated = m_inventory_updated;
2041 m_inventory_updated = false;
2045 // Copies the inventory of the local player to parameter
2046 void Client::getLocalInventory(Inventory &dst)
2048 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2049 Player *player = m_env.getLocalPlayer();
2050 assert(player != NULL);
2051 dst = player->inventory;
2054 InventoryContext *Client::getInventoryContext()
2056 return &m_inventory_context;
2059 Inventory* Client::getInventory(InventoryContext *c, std::string id)
2061 if(id == "current_player")
2063 assert(c->current_player);
2064 return &(c->current_player->inventory);
2068 std::string id0 = fn.next(":");
2070 if(id0 == "nodemeta")
2073 p.X = stoi(fn.next(","));
2074 p.Y = stoi(fn.next(","));
2075 p.Z = stoi(fn.next(","));
2076 NodeMetadata* meta = getNodeMetadata(p);
2078 return meta->getInventory();
2079 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
2080 <<"no metadata found"<<std::endl;
2084 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
2087 void Client::inventoryAction(InventoryAction *a)
2089 sendInventoryAction(a);
2092 ClientActiveObject * Client::getSelectedActiveObject(
2094 v3f from_pos_f_on_map,
2095 core::line3d<f32> shootline_on_map
2098 core::array<DistanceSortedActiveObject> objects;
2100 m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2102 //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2105 // After this, the closest object is the first in the array.
2108 for(u32 i=0; i<objects.size(); i++)
2110 ClientActiveObject *obj = objects[i].obj;
2112 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2113 if(selection_box == NULL)
2116 v3f pos = obj->getPosition();
2118 core::aabbox3d<f32> offsetted_box(
2119 selection_box->MinEdge + pos,
2120 selection_box->MaxEdge + pos
2123 if(offsetted_box.intersectsWithLine(shootline_on_map))
2125 //infostream<<"Returning selected object"<<std::endl;
2130 //infostream<<"No object selected; returning NULL."<<std::endl;
2134 void Client::printDebugInfo(std::ostream &os)
2136 //JMutexAutoLock lock1(m_fetchblock_mutex);
2137 /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2139 os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2140 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2141 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2145 u32 Client::getDayNightRatio()
2147 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2148 return m_env.getDayNightRatio();
2153 Player *player = m_env.getLocalPlayer();
2154 assert(player != NULL);
2158 void Client::setTempMod(v3s16 p, NodeMod mod)
2160 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2161 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2163 core::map<v3s16, MapBlock*> affected_blocks;
2164 ((ClientMap&)m_env.getMap()).setTempMod(p, mod,
2167 for(core::map<v3s16, MapBlock*>::Iterator
2168 i = affected_blocks.getIterator();
2169 i.atEnd() == false; i++)
2171 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2175 void Client::clearTempMod(v3s16 p)
2177 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2178 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2180 core::map<v3s16, MapBlock*> affected_blocks;
2181 ((ClientMap&)m_env.getMap()).clearTempMod(p,
2184 for(core::map<v3s16, MapBlock*>::Iterator
2185 i = affected_blocks.getIterator();
2186 i.atEnd() == false; i++)
2188 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2192 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
2194 /*infostream<<"Client::addUpdateMeshTask(): "
2195 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2198 MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2203 Create a task to update the mesh of the block
2206 MeshMakeData *data = new MeshMakeData;
2209 //TimeTaker timer("data fill");
2211 // Debug: 1-6ms, avg=2ms
2212 data->fill(getDayNightRatio(), b);
2216 //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2218 // Add task to queue
2219 m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server);
2221 /*infostream<<"Mesh update input queue size is "
2222 <<m_mesh_update_thread.m_queue_in.size()
2226 // Temporary test: make mesh directly in here
2228 //TimeTaker timer("make mesh");
2230 scene::SMesh *mesh_new = NULL;
2231 mesh_new = makeMapBlockMesh(data);
2232 b->replaceMesh(mesh_new);
2238 Mark mesh as non-expired at this point so that it can already
2239 be marked as expired again if the data changes
2241 b->setMeshExpired(false);
2244 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
2248 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2249 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2254 v3s16 p = blockpos + v3s16(0,0,0);
2255 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2256 addUpdateMeshTask(p, ack_to_server);
2258 catch(InvalidPositionException &e){}
2261 v3s16 p = blockpos + v3s16(-1,0,0);
2262 addUpdateMeshTask(p);
2264 catch(InvalidPositionException &e){}
2266 v3s16 p = blockpos + v3s16(0,-1,0);
2267 addUpdateMeshTask(p);
2269 catch(InvalidPositionException &e){}
2271 v3s16 p = blockpos + v3s16(0,0,-1);
2272 addUpdateMeshTask(p);
2274 catch(InvalidPositionException &e){}
2277 ClientEvent Client::getClientEvent()
2279 if(m_client_event_queue.size() == 0)
2282 event.type = CE_NONE;
2285 return m_client_event_queue.pop_front();
2288 float Client::getRTT(void)
2291 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2292 } catch(con::PeerNotFoundException &e){
2297 // IGameDef interface
2299 IToolDefManager* Client::getToolDefManager()
2303 INodeDefManager* Client::getNodeDefManager()
2307 ITextureSource* Client::getTextureSource()