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"<<std::endl;
1512 std::string datastring((char*)&data[2], datasize-2);
1513 std::istringstream is(datastring, std::ios_base::binary);
1515 // Stop threads while updating content definitions
1516 m_mesh_update_thread.stop();
1518 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1519 m_tooldef->deSerialize(tmp_is);
1522 m_mesh_update_thread.setRun(true);
1523 m_mesh_update_thread.Start();
1525 else if(command == TOCLIENT_TEXTURES)
1527 infostream<<"Client: Received textures: packet size: "<<datasize
1530 io::IFileSystem *irrfs = m_device->getFileSystem();
1531 video::IVideoDriver *vdrv = m_device->getVideoDriver();
1533 std::string datastring((char*)&data[2], datasize-2);
1534 std::istringstream is(datastring, std::ios_base::binary);
1536 // Stop threads while updating content definitions
1537 m_mesh_update_thread.stop();
1541 u32 number of textures
1549 int num_textures = readU32(is);
1550 infostream<<"Client: Received textures: count: "<<num_textures
1552 for(int i=0; i<num_textures; i++){
1553 std::string name = deSerializeString(is);
1554 std::string data = deSerializeLongString(is);
1555 // Silly irrlicht's const-incorrectness
1556 Buffer<char> data_rw(data.c_str(), data.size());
1557 // Create an irrlicht memory file
1558 io::IReadFile *rfile = irrfs->createMemoryReadFile(
1559 *data_rw, data.size(), "_tempreadfile");
1562 video::IImage *img = vdrv->createImageFromFile(rfile);
1564 errorstream<<"Client: Cannot create image from data of "
1565 <<"received texture \""<<name<<"\""<<std::endl;
1569 m_tsrc->insertSourceImage(name, img);
1574 // Rebuild inherited images and recreate textures
1575 m_tsrc->rebuildImagesAndTextures();
1577 // Update texture atlas
1578 if(g_settings->getBool("enable_texture_atlas"))
1579 m_tsrc->buildMainAtlas(this);
1581 // Update node textures
1582 m_nodedef->updateTextures(m_tsrc);
1585 m_mesh_update_thread.setRun(true);
1586 m_mesh_update_thread.Start();
1589 event.type = CE_TEXTURES_UPDATED;
1590 m_client_event_queue.push_back(event);
1594 infostream<<"Client: Ignoring unknown command "
1595 <<command<<std::endl;
1599 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1601 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1602 m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1605 void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
1606 v3s16 nodepos_oversurface, u16 item)
1608 if(connectedAndInitialized() == false){
1609 infostream<<"Client::groundAction() "
1610 "cancelled (not connected)"
1619 [3] v3s16 nodepos_undersurface
1620 [9] v3s16 nodepos_abovesurface
1625 2: stop digging (all parameters ignored)
1626 3: digging completed
1628 u8 datasize = 2 + 1 + 6 + 6 + 2;
1629 SharedBuffer<u8> data(datasize);
1630 writeU16(&data[0], TOSERVER_GROUND_ACTION);
1631 writeU8(&data[2], action);
1632 writeV3S16(&data[3], nodepos_undersurface);
1633 writeV3S16(&data[9], nodepos_oversurface);
1634 writeU16(&data[15], item);
1635 Send(0, data, true);
1638 void Client::clickActiveObject(u8 button, u16 id, u16 item_i)
1640 if(connectedAndInitialized() == false){
1641 infostream<<"Client::clickActiveObject() "
1642 "cancelled (not connected)"
1647 Player *player = m_env.getLocalPlayer();
1651 ClientActiveObject *obj = m_env.getActiveObject(id);
1654 ToolItem *titem = NULL;
1655 std::string toolname = "";
1657 InventoryList *mlist = player->inventory.getList("main");
1660 InventoryItem *item = mlist->getItem(item_i);
1661 if(item && (std::string)item->getName() == "ToolItem")
1663 titem = (ToolItem*)item;
1664 toolname = titem->getToolName();
1668 v3f playerpos = player->getPosition();
1669 v3f objpos = obj->getPosition();
1670 v3f dir = (objpos - playerpos).normalize();
1672 bool disable_send = obj->directReportPunch(toolname, dir);
1682 [2] u8 button (0=left, 1=right)
1686 u8 datasize = 2 + 1 + 6 + 2 + 2;
1687 SharedBuffer<u8> data(datasize);
1688 writeU16(&data[0], TOSERVER_CLICK_ACTIVEOBJECT);
1689 writeU8(&data[2], button);
1690 writeU16(&data[3], id);
1691 writeU16(&data[5], item_i);
1692 Send(0, data, true);
1695 void Client::sendSignNodeText(v3s16 p, std::string text)
1703 std::ostringstream os(std::ios_base::binary);
1707 writeU16(buf, TOSERVER_SIGNNODETEXT);
1708 os.write((char*)buf, 2);
1712 os.write((char*)buf, 6);
1714 u16 textlen = text.size();
1715 // Write text length
1716 writeS16(buf, textlen);
1717 os.write((char*)buf, 2);
1720 os.write((char*)text.c_str(), textlen);
1723 std::string s = os.str();
1724 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1726 Send(0, data, true);
1729 void Client::sendInventoryAction(InventoryAction *a)
1731 std::ostringstream os(std::ios_base::binary);
1735 writeU16(buf, TOSERVER_INVENTORY_ACTION);
1736 os.write((char*)buf, 2);
1741 std::string s = os.str();
1742 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1744 Send(0, data, true);
1747 void Client::sendChatMessage(const std::wstring &message)
1749 std::ostringstream os(std::ios_base::binary);
1753 writeU16(buf, TOSERVER_CHAT_MESSAGE);
1754 os.write((char*)buf, 2);
1757 writeU16(buf, message.size());
1758 os.write((char*)buf, 2);
1761 for(u32 i=0; i<message.size(); i++)
1765 os.write((char*)buf, 2);
1769 std::string s = os.str();
1770 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1772 Send(0, data, true);
1775 void Client::sendChangePassword(const std::wstring oldpassword,
1776 const std::wstring newpassword)
1778 Player *player = m_env.getLocalPlayer();
1782 std::string playername = player->getName();
1783 std::string oldpwd = translatePassword(playername, oldpassword);
1784 std::string newpwd = translatePassword(playername, newpassword);
1786 std::ostringstream os(std::ios_base::binary);
1787 u8 buf[2+PASSWORD_SIZE*2];
1789 [0] u16 TOSERVER_PASSWORD
1790 [2] u8[28] old password
1791 [30] u8[28] new password
1794 writeU16(buf, TOSERVER_PASSWORD);
1795 for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1797 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1798 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1800 buf[2+PASSWORD_SIZE-1] = 0;
1801 buf[30+PASSWORD_SIZE-1] = 0;
1802 os.write((char*)buf, 2+PASSWORD_SIZE*2);
1805 std::string s = os.str();
1806 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1808 Send(0, data, true);
1812 void Client::sendDamage(u8 damage)
1814 DSTACK(__FUNCTION_NAME);
1815 std::ostringstream os(std::ios_base::binary);
1817 writeU16(os, TOSERVER_DAMAGE);
1818 writeU8(os, damage);
1821 std::string s = os.str();
1822 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1824 Send(0, data, true);
1827 void Client::sendRespawn()
1829 DSTACK(__FUNCTION_NAME);
1830 std::ostringstream os(std::ios_base::binary);
1832 writeU16(os, TOSERVER_RESPAWN);
1835 std::string s = os.str();
1836 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1838 Send(0, data, true);
1841 void Client::sendPlayerPos()
1843 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1845 Player *myplayer = m_env.getLocalPlayer();
1846 if(myplayer == NULL)
1851 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1852 our_peer_id = m_con.GetPeerID();
1855 // Set peer id if not set already
1856 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1857 myplayer->peer_id = our_peer_id;
1858 // Check that an existing peer_id is the same as the connection's
1859 assert(myplayer->peer_id == our_peer_id);
1861 v3f pf = myplayer->getPosition();
1862 v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1863 v3f sf = myplayer->getSpeed();
1864 v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1865 s32 pitch = myplayer->getPitch() * 100;
1866 s32 yaw = myplayer->getYaw() * 100;
1871 [2] v3s32 position*100
1872 [2+12] v3s32 speed*100
1873 [2+12+12] s32 pitch*100
1874 [2+12+12+4] s32 yaw*100
1877 SharedBuffer<u8> data(2+12+12+4+4);
1878 writeU16(&data[0], TOSERVER_PLAYERPOS);
1879 writeV3S32(&data[2], position);
1880 writeV3S32(&data[2+12], speed);
1881 writeS32(&data[2+12+12], pitch);
1882 writeS32(&data[2+12+12+4], yaw);
1884 // Send as unreliable
1885 Send(0, data, false);
1888 void Client::sendPlayerItem(u16 item)
1890 Player *myplayer = m_env.getLocalPlayer();
1891 if(myplayer == NULL)
1894 u16 our_peer_id = m_con.GetPeerID();
1896 // Set peer id if not set already
1897 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1898 myplayer->peer_id = our_peer_id;
1899 // Check that an existing peer_id is the same as the connection's
1900 assert(myplayer->peer_id == our_peer_id);
1902 SharedBuffer<u8> data(2+2);
1903 writeU16(&data[0], TOSERVER_PLAYERITEM);
1904 writeU16(&data[2], item);
1907 Send(0, data, true);
1910 void Client::removeNode(v3s16 p)
1912 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1914 core::map<v3s16, MapBlock*> modified_blocks;
1918 //TimeTaker t("removeNodeAndUpdate", m_device);
1919 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1921 catch(InvalidPositionException &e)
1925 for(core::map<v3s16, MapBlock * >::Iterator
1926 i = modified_blocks.getIterator();
1927 i.atEnd() == false; i++)
1929 v3s16 p = i.getNode()->getKey();
1930 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1931 addUpdateMeshTaskWithEdge(p);
1935 void Client::addNode(v3s16 p, MapNode n)
1937 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1939 TimeTaker timer1("Client::addNode()");
1941 core::map<v3s16, MapBlock*> modified_blocks;
1945 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1946 std::string st = std::string("");
1947 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st);
1949 catch(InvalidPositionException &e)
1952 //TimeTaker timer2("Client::addNode(): updateMeshes");
1954 for(core::map<v3s16, MapBlock * >::Iterator
1955 i = modified_blocks.getIterator();
1956 i.atEnd() == false; i++)
1958 v3s16 p = i.getNode()->getKey();
1959 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1960 addUpdateMeshTaskWithEdge(p);
1964 void Client::updateCamera(v3f pos, v3f dir, f32 fov)
1966 m_env.getClientMap().updateCamera(pos, dir, fov);
1969 void Client::renderPostFx()
1971 m_env.getClientMap().renderPostFx();
1974 MapNode Client::getNode(v3s16 p)
1976 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1977 return m_env.getMap().getNode(p);
1980 NodeMetadata* Client::getNodeMetadata(v3s16 p)
1982 return m_env.getMap().getNodeMetadata(p);
1985 LocalPlayer* Client::getLocalPlayer()
1987 return m_env.getLocalPlayer();
1990 void Client::setPlayerControl(PlayerControl &control)
1992 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1993 LocalPlayer *player = m_env.getLocalPlayer();
1994 assert(player != NULL);
1995 player->control = control;
1998 void Client::selectPlayerItem(u16 item)
2000 LocalPlayer *player = m_env.getLocalPlayer();
2001 assert(player != NULL);
2003 player->wieldItem(item);
2005 sendPlayerItem(item);
2008 // Returns true if the inventory of the local player has been
2009 // updated from the server. If it is true, it is set to false.
2010 bool Client::getLocalInventoryUpdated()
2012 // m_inventory_updated is behind envlock
2013 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2014 bool updated = m_inventory_updated;
2015 m_inventory_updated = false;
2019 // Copies the inventory of the local player to parameter
2020 void Client::getLocalInventory(Inventory &dst)
2022 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2023 Player *player = m_env.getLocalPlayer();
2024 assert(player != NULL);
2025 dst = player->inventory;
2028 InventoryContext *Client::getInventoryContext()
2030 return &m_inventory_context;
2033 Inventory* Client::getInventory(InventoryContext *c, std::string id)
2035 if(id == "current_player")
2037 assert(c->current_player);
2038 return &(c->current_player->inventory);
2042 std::string id0 = fn.next(":");
2044 if(id0 == "nodemeta")
2047 p.X = stoi(fn.next(","));
2048 p.Y = stoi(fn.next(","));
2049 p.Z = stoi(fn.next(","));
2050 NodeMetadata* meta = getNodeMetadata(p);
2052 return meta->getInventory();
2053 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
2054 <<"no metadata found"<<std::endl;
2058 infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
2061 void Client::inventoryAction(InventoryAction *a)
2063 sendInventoryAction(a);
2066 ClientActiveObject * Client::getSelectedActiveObject(
2068 v3f from_pos_f_on_map,
2069 core::line3d<f32> shootline_on_map
2072 core::array<DistanceSortedActiveObject> objects;
2074 m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2076 //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2079 // After this, the closest object is the first in the array.
2082 for(u32 i=0; i<objects.size(); i++)
2084 ClientActiveObject *obj = objects[i].obj;
2086 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2087 if(selection_box == NULL)
2090 v3f pos = obj->getPosition();
2092 core::aabbox3d<f32> offsetted_box(
2093 selection_box->MinEdge + pos,
2094 selection_box->MaxEdge + pos
2097 if(offsetted_box.intersectsWithLine(shootline_on_map))
2099 //infostream<<"Returning selected object"<<std::endl;
2104 //infostream<<"No object selected; returning NULL."<<std::endl;
2108 void Client::printDebugInfo(std::ostream &os)
2110 //JMutexAutoLock lock1(m_fetchblock_mutex);
2111 /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2113 os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2114 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2115 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2119 u32 Client::getDayNightRatio()
2121 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2122 return m_env.getDayNightRatio();
2127 Player *player = m_env.getLocalPlayer();
2128 assert(player != NULL);
2132 void Client::setTempMod(v3s16 p, NodeMod mod)
2134 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2135 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2137 core::map<v3s16, MapBlock*> affected_blocks;
2138 ((ClientMap&)m_env.getMap()).setTempMod(p, mod,
2141 for(core::map<v3s16, MapBlock*>::Iterator
2142 i = affected_blocks.getIterator();
2143 i.atEnd() == false; i++)
2145 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2149 void Client::clearTempMod(v3s16 p)
2151 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2152 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2154 core::map<v3s16, MapBlock*> affected_blocks;
2155 ((ClientMap&)m_env.getMap()).clearTempMod(p,
2158 for(core::map<v3s16, MapBlock*>::Iterator
2159 i = affected_blocks.getIterator();
2160 i.atEnd() == false; i++)
2162 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2166 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
2168 /*infostream<<"Client::addUpdateMeshTask(): "
2169 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2172 MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2177 Create a task to update the mesh of the block
2180 MeshMakeData *data = new MeshMakeData;
2183 //TimeTaker timer("data fill");
2185 // Debug: 1-6ms, avg=2ms
2186 data->fill(getDayNightRatio(), b);
2190 //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2192 // Add task to queue
2193 m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server);
2195 /*infostream<<"Mesh update input queue size is "
2196 <<m_mesh_update_thread.m_queue_in.size()
2200 // Temporary test: make mesh directly in here
2202 //TimeTaker timer("make mesh");
2204 scene::SMesh *mesh_new = NULL;
2205 mesh_new = makeMapBlockMesh(data);
2206 b->replaceMesh(mesh_new);
2212 Mark mesh as non-expired at this point so that it can already
2213 be marked as expired again if the data changes
2215 b->setMeshExpired(false);
2218 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
2222 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2223 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2228 v3s16 p = blockpos + v3s16(0,0,0);
2229 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2230 addUpdateMeshTask(p, ack_to_server);
2232 catch(InvalidPositionException &e){}
2235 v3s16 p = blockpos + v3s16(-1,0,0);
2236 addUpdateMeshTask(p);
2238 catch(InvalidPositionException &e){}
2240 v3s16 p = blockpos + v3s16(0,-1,0);
2241 addUpdateMeshTask(p);
2243 catch(InvalidPositionException &e){}
2245 v3s16 p = blockpos + v3s16(0,0,-1);
2246 addUpdateMeshTask(p);
2248 catch(InvalidPositionException &e){}
2251 ClientEvent Client::getClientEvent()
2253 if(m_client_event_queue.size() == 0)
2256 event.type = CE_NONE;
2259 return m_client_event_queue.pop_front();
2262 float Client::getRTT(void)
2265 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2266 } catch(con::PeerNotFoundException &e){
2271 // IGameDef interface
2273 IToolDefManager* Client::getToolDefManager()
2277 INodeDefManager* Client::getNodeDefManager()
2281 ITextureSource* Client::getTextureSource()