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"
38 QueuedMeshUpdate::QueuedMeshUpdate():
41 ack_block_to_server(false)
45 QueuedMeshUpdate::~QueuedMeshUpdate()
55 MeshUpdateQueue::MeshUpdateQueue()
60 MeshUpdateQueue::~MeshUpdateQueue()
62 JMutexAutoLock lock(m_mutex);
64 core::list<QueuedMeshUpdate*>::Iterator i;
65 for(i=m_queue.begin(); i!=m_queue.end(); i++)
67 QueuedMeshUpdate *q = *i;
73 peer_id=0 adds with nobody to send to
75 void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server)
77 DSTACK(__FUNCTION_NAME);
81 JMutexAutoLock lock(m_mutex);
84 Find if block is already in queue.
85 If it is, update the data and quit.
87 core::list<QueuedMeshUpdate*>::Iterator i;
88 for(i=m_queue.begin(); i!=m_queue.end(); i++)
90 QueuedMeshUpdate *q = *i;
96 if(ack_block_to_server)
97 q->ack_block_to_server = true;
105 QueuedMeshUpdate *q = new QueuedMeshUpdate;
108 q->ack_block_to_server = ack_block_to_server;
109 m_queue.push_back(q);
112 // Returned pointer must be deleted
113 // Returns NULL if queue is empty
114 QueuedMeshUpdate * MeshUpdateQueue::pop()
116 JMutexAutoLock lock(m_mutex);
118 core::list<QueuedMeshUpdate*>::Iterator i = m_queue.begin();
119 if(i == m_queue.end())
121 QueuedMeshUpdate *q = *i;
130 void * MeshUpdateThread::Thread()
134 DSTACK(__FUNCTION_NAME);
136 BEGIN_DEBUG_EXCEPTION_HANDLER
140 /*// Wait for output queue to flush.
141 // Allow 2 in queue, this makes less frametime jitter.
142 // Umm actually, there is no much difference
143 if(m_queue_out.size() >= 2)
149 QueuedMeshUpdate *q = m_queue_in.pop();
156 ScopeProfiler sp(g_profiler, "mesh make");
158 scene::SMesh *mesh_new = NULL;
159 mesh_new = makeMapBlockMesh(q->data);
164 r.ack_block_to_server = q->ack_block_to_server;
166 /*dstream<<"MeshUpdateThread: Processed "
167 <<"("<<q->p.X<<","<<q->p.Y<<","<<q->p.Z<<")"
170 m_queue_out.push_back(r);
175 END_DEBUG_EXCEPTION_HANDLER
181 IrrlichtDevice *device,
182 const char *playername,
183 std::string password,
184 MapDrawControl &control):
185 m_mesh_update_thread(),
187 new ClientMap(this, control,
188 device->getSceneManager()->getRootSceneNode(),
189 device->getSceneManager(), 666),
190 device->getSceneManager()
192 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
194 m_server_ser_ver(SER_FMT_VER_INVALID),
195 m_inventory_updated(false),
198 m_password(password),
199 m_access_denied(false)
201 m_packetcounter_timer = 0.0;
202 //m_delete_unused_sectors_timer = 0.0;
203 m_connection_reinit_timer = 0.0;
204 m_avg_rtt_timer = 0.0;
205 m_playerpos_send_timer = 0.0;
206 m_ignore_damage_timer = 0.0;
208 //m_env_mutex.Init();
209 //m_con_mutex.Init();
211 m_mesh_update_thread.Start();
217 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
219 Player *player = new LocalPlayer();
221 player->updateName(playername);
223 m_env.addPlayer(player);
225 // Initialize player in the inventory context
226 m_inventory_context.current_player = player;
233 //JMutexAutoLock conlock(m_con_mutex); //bulk comment-out
237 m_mesh_update_thread.setRun(false);
238 while(m_mesh_update_thread.IsRunning())
242 void Client::connect(Address address)
244 DSTACK(__FUNCTION_NAME);
245 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
246 m_con.setTimeoutMs(0);
247 m_con.Connect(address);
250 bool Client::connectedAndInitialized()
252 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
254 if(m_con.Connected() == false)
257 if(m_server_ser_ver == SER_FMT_VER_INVALID)
263 void Client::step(float dtime)
265 DSTACK(__FUNCTION_NAME);
271 if(m_ignore_damage_timer > dtime)
272 m_ignore_damage_timer -= dtime;
274 m_ignore_damage_timer = 0.0;
276 //dstream<<"Client steps "<<dtime<<std::endl;
279 //TimeTaker timer("ReceiveAll()", m_device);
285 //TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device);
287 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
288 m_con.RunTimeouts(dtime);
295 float &counter = m_packetcounter_timer;
301 dout_client<<"Client packetcounter (20s):"<<std::endl;
302 m_packetcounter.print(dout_client);
303 m_packetcounter.clear();
307 // Get connection status
308 bool connected = connectedAndInitialized();
313 Delete unused sectors
315 NOTE: This jams the game for a while because deleting sectors
319 float &counter = m_delete_unused_sectors_timer;
327 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
329 core::list<v3s16> deleted_blocks;
331 float delete_unused_sectors_timeout =
332 g_settings->getFloat("client_delete_unused_sectors_timeout");
334 // Delete sector blocks
335 /*u32 num = m_env.getMap().unloadUnusedData
336 (delete_unused_sectors_timeout,
337 true, &deleted_blocks);*/
339 // Delete whole sectors
340 m_env.getMap().unloadUnusedData
341 (delete_unused_sectors_timeout,
344 if(deleted_blocks.size() > 0)
346 /*dstream<<DTIME<<"Client: Deleted blocks of "<<num
347 <<" unused sectors"<<std::endl;*/
348 /*dstream<<DTIME<<"Client: Deleted "<<num
349 <<" unused sectors"<<std::endl;*/
355 // Env is locked so con can be locked.
356 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
358 core::list<v3s16>::Iterator i = deleted_blocks.begin();
359 core::list<v3s16> sendlist;
362 if(sendlist.size() == 255 || i == deleted_blocks.end())
364 if(sendlist.size() == 0)
373 u32 replysize = 2+1+6*sendlist.size();
374 SharedBuffer<u8> reply(replysize);
375 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
376 reply[2] = sendlist.size();
378 for(core::list<v3s16>::Iterator
379 j = sendlist.begin();
380 j != sendlist.end(); j++)
382 writeV3S16(&reply[2+1+6*k], *j);
385 m_con.Send(PEER_ID_SERVER, 1, reply, true);
387 if(i == deleted_blocks.end())
393 sendlist.push_back(*i);
401 if(connected == false)
403 float &counter = m_connection_reinit_timer;
409 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
411 Player *myplayer = m_env.getLocalPlayer();
412 assert(myplayer != NULL);
414 // Send TOSERVER_INIT
415 // [0] u16 TOSERVER_INIT
416 // [2] u8 SER_FMT_VER_HIGHEST
417 // [3] u8[20] player_name
418 // [23] u8[28] password (new in some version)
419 // [51] u16 client network protocol version (new in some version)
420 SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2);
421 writeU16(&data[0], TOSERVER_INIT);
422 writeU8(&data[2], SER_FMT_VER_HIGHEST);
424 memset((char*)&data[3], 0, PLAYERNAME_SIZE);
425 snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
427 /*dstream<<"Client: sending initial password hash: \""<<m_password<<"\""
430 memset((char*)&data[23], 0, PASSWORD_SIZE);
431 snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
433 // This should be incremented in each version
434 writeU16(&data[51], 3);
436 // Send as unreliable
437 Send(0, data, false);
440 // Not connected, return
445 Do stuff if connected
449 Run Map's timers and unload unused data
451 const float map_timer_and_unload_dtime = 5.25;
452 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
454 ScopeProfiler sp(g_profiler, "Client: map timer and unload");
455 core::list<v3s16> deleted_blocks;
456 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
457 g_settings->getFloat("client_unload_unused_data_timeout"),
460 /*if(deleted_blocks.size() > 0)
461 dstream<<"Client: Unloaded "<<deleted_blocks.size()
462 <<" unused blocks"<<std::endl;*/
466 NOTE: This loop is intentionally iterated the way it is.
469 core::list<v3s16>::Iterator i = deleted_blocks.begin();
470 core::list<v3s16> sendlist;
473 if(sendlist.size() == 255 || i == deleted_blocks.end())
475 if(sendlist.size() == 0)
484 u32 replysize = 2+1+6*sendlist.size();
485 SharedBuffer<u8> reply(replysize);
486 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
487 reply[2] = sendlist.size();
489 for(core::list<v3s16>::Iterator
490 j = sendlist.begin();
491 j != sendlist.end(); j++)
493 writeV3S16(&reply[2+1+6*k], *j);
496 m_con.Send(PEER_ID_SERVER, 1, reply, true);
498 if(i == deleted_blocks.end())
504 sendlist.push_back(*i);
514 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
516 // Control local player (0ms)
517 LocalPlayer *player = m_env.getLocalPlayer();
518 assert(player != NULL);
519 player->applyControl(dtime);
521 //TimeTaker envtimer("env step", m_device);
530 ClientEnvEvent event = m_env.getClientEvent();
531 if(event.type == CEE_NONE)
535 else if(event.type == CEE_PLAYER_DAMAGE)
537 if(m_ignore_damage_timer <= 0)
539 u8 damage = event.player_damage.amount;
542 // Add to ClientEvent queue
544 event.type = CE_PLAYER_DAMAGE;
545 event.player_damage.amount = damage;
546 m_client_event_queue.push_back(event);
556 float &counter = m_avg_rtt_timer;
561 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
562 // connectedAndInitialized() is true, peer exists.
563 con::Peer *peer = m_con.GetPeer(PEER_ID_SERVER);
564 dstream<<DTIME<<"Client: avg_rtt="<<peer->avg_rtt<<std::endl;
569 Send player position to server
572 float &counter = m_playerpos_send_timer;
582 Replace updated meshes
585 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
587 //TimeTaker timer("** Processing mesh update result queue");
590 /*dstream<<"Mesh update result queue size is "
591 <<m_mesh_update_thread.m_queue_out.size()
594 while(m_mesh_update_thread.m_queue_out.size() > 0)
596 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
597 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
600 block->replaceMesh(r.mesh);
602 if(r.ack_block_to_server)
604 /*dstream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
605 <<","<<r.p.Z<<")"<<std::endl;*/
616 u32 replysize = 2+1+6;
617 SharedBuffer<u8> reply(replysize);
618 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
620 writeV3S16(&reply[3], r.p);
622 m_con.Send(PEER_ID_SERVER, 1, reply, true);
628 // Virtual methods from con::PeerHandler
629 void Client::peerAdded(con::Peer *peer)
631 derr_client<<"Client::peerAdded(): peer->id="
632 <<peer->id<<std::endl;
634 void Client::deletingPeer(con::Peer *peer, bool timeout)
636 derr_client<<"Client::deletingPeer(): "
637 "Server Peer is getting deleted "
638 <<"(timeout="<<timeout<<")"<<std::endl;
641 void Client::ReceiveAll()
643 DSTACK(__FUNCTION_NAME);
649 catch(con::NoIncomingDataException &e)
653 catch(con::InvalidIncomingDataException &e)
655 dout_client<<DTIME<<"Client::ReceiveAll(): "
656 "InvalidIncomingDataException: what()="
657 <<e.what()<<std::endl;
662 void Client::Receive()
664 DSTACK(__FUNCTION_NAME);
665 u32 data_maxsize = 200000;
666 Buffer<u8> data(data_maxsize);
670 //TimeTaker t1("con mutex and receive", m_device);
671 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
672 datasize = m_con.Receive(sender_peer_id, *data, data_maxsize);
674 //TimeTaker t1("ProcessData", m_device);
675 ProcessData(*data, datasize, sender_peer_id);
679 sender_peer_id given to this shall be quaranteed to be a valid peer
681 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
683 DSTACK(__FUNCTION_NAME);
685 // Ignore packets that don't even fit a command
688 m_packetcounter.add(60000);
692 ToClientCommand command = (ToClientCommand)readU16(&data[0]);
694 //dstream<<"Client: received command="<<command<<std::endl;
695 m_packetcounter.add((u16)command);
698 If this check is removed, be sure to change the queue
699 system to know the ids
701 if(sender_peer_id != PEER_ID_SERVER)
703 dout_client<<DTIME<<"Client::ProcessData(): Discarding data not "
704 "coming from server: peer_id="<<sender_peer_id
711 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
712 // All data is coming from the server
713 // PeerNotFoundException is handled by caller.
714 peer = m_con.GetPeer(PEER_ID_SERVER);
717 u8 ser_version = m_server_ser_ver;
719 //dstream<<"Client received command="<<(int)command<<std::endl;
721 if(command == TOCLIENT_INIT)
726 u8 deployed = data[2];
728 dout_client<<DTIME<<"Client: TOCLIENT_INIT received with "
729 "deployed="<<((int)deployed&0xff)<<std::endl;
731 if(deployed < SER_FMT_VER_LOWEST
732 || deployed > SER_FMT_VER_HIGHEST)
734 derr_client<<DTIME<<"Client: TOCLIENT_INIT: Server sent "
735 <<"unsupported ser_fmt_ver"<<std::endl;
739 m_server_ser_ver = deployed;
741 // Get player position
742 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
743 if(datasize >= 2+1+6)
744 playerpos_s16 = readV3S16(&data[2+1]);
745 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
748 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
750 // Set player position
751 Player *player = m_env.getLocalPlayer();
752 assert(player != NULL);
753 player->setPosition(playerpos_f);
756 if(datasize >= 2+1+6+8)
759 m_map_seed = readU64(&data[2+1+6]);
760 dstream<<"Client: received map seed: "<<m_map_seed<<std::endl;
765 SharedBuffer<u8> reply(replysize);
766 writeU16(&reply[0], TOSERVER_INIT2);
768 m_con.Send(PEER_ID_SERVER, 1, reply, true);
773 if(command == TOCLIENT_ACCESS_DENIED)
775 // The server didn't like our password. Note, this needs
776 // to be processed even if the serialisation format has
777 // not been agreed yet, the same as TOCLIENT_INIT.
778 m_access_denied = true;
779 m_access_denied_reason = L"Unknown";
782 std::string datastring((char*)&data[2], datasize-2);
783 std::istringstream is(datastring, std::ios_base::binary);
784 m_access_denied_reason = deSerializeWideString(is);
789 if(ser_version == SER_FMT_VER_INVALID)
791 dout_client<<DTIME<<"WARNING: Client: Server serialization"
792 " format invalid or not initialized."
793 " Skipping incoming command="<<command<<std::endl;
797 // Just here to avoid putting the two if's together when
798 // making some copypasta
801 if(command == TOCLIENT_REMOVENODE)
806 p.X = readS16(&data[2]);
807 p.Y = readS16(&data[4]);
808 p.Z = readS16(&data[6]);
810 //TimeTaker t1("TOCLIENT_REMOVENODE");
812 // This will clear the cracking animation after digging
813 ((ClientMap&)m_env.getMap()).clearTempMod(p);
817 else if(command == TOCLIENT_ADDNODE)
819 if(datasize < 8 + MapNode::serializedLength(ser_version))
823 p.X = readS16(&data[2]);
824 p.Y = readS16(&data[4]);
825 p.Z = readS16(&data[6]);
827 //TimeTaker t1("TOCLIENT_ADDNODE");
830 n.deSerialize(&data[8], ser_version);
834 else if(command == TOCLIENT_BLOCKDATA)
836 // Ignore too small packet
841 p.X = readS16(&data[2]);
842 p.Y = readS16(&data[4]);
843 p.Z = readS16(&data[6]);
845 /*dout_client<<DTIME<<"Client: Thread: BLOCKDATA for ("
846 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
847 /*dstream<<DTIME<<"Client: Thread: BLOCKDATA for ("
848 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
850 std::string datastring((char*)&data[8], datasize-8);
851 std::istringstream istr(datastring, std::ios_base::binary);
857 sector = m_env.getMap().emergeSector(p2d);
859 assert(sector->getPos() == p2d);
861 //TimeTaker timer("MapBlock deSerialize");
864 block = sector->getBlockNoCreateNoEx(p.Y);
868 Update an existing block
870 //dstream<<"Updating"<<std::endl;
871 block->deSerialize(istr, ser_version);
878 //dstream<<"Creating new"<<std::endl;
879 block = new MapBlock(&m_env.getMap(), p);
880 block->deSerialize(istr, ser_version);
881 sector->insertBlock(block);
885 mod.type = NODEMOD_CHANGECONTENT;
886 mod.param = CONTENT_MESE;
887 block->setTempMod(v3s16(8,10,8), mod);
888 block->setTempMod(v3s16(8,9,8), mod);
889 block->setTempMod(v3s16(8,8,8), mod);
890 block->setTempMod(v3s16(8,7,8), mod);
891 block->setTempMod(v3s16(8,6,8), mod);*/
905 u32 replysize = 2+1+6;
906 SharedBuffer<u8> reply(replysize);
907 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
909 writeV3S16(&reply[3], p);
911 m_con.Send(PEER_ID_SERVER, 1, reply, true);
915 Update Mesh of this block and blocks at x-, y- and z-.
916 Environment should not be locked as it interlocks with the
917 main thread, from which is will want to retrieve textures.
920 //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
922 Add it to mesh update queue and set it to be acknowledged after update.
924 //std::cerr<<"Adding mesh update task for received block"<<std::endl;
925 addUpdateMeshTaskWithEdge(p, true);
927 else if(command == TOCLIENT_PLAYERPOS)
929 dstream<<"WARNING: Received deprecated TOCLIENT_PLAYERPOS"
933 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
934 our_peer_id = m_con.GetPeerID();
936 // Cancel if we don't have a peer id
937 if(our_peer_id == PEER_ID_INEXISTENT){
938 dout_client<<DTIME<<"TOCLIENT_PLAYERPOS cancelled: "
945 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
947 u32 player_size = 2+12+12+4+4;
949 u32 player_count = (datasize-2) / player_size;
951 for(u32 i=0; i<player_count; i++)
953 u16 peer_id = readU16(&data[start]);
955 Player *player = m_env.getPlayer(peer_id);
957 // Skip if player doesn't exist
960 start += player_size;
964 // Skip if player is local player
965 if(player->isLocal())
967 start += player_size;
971 v3s32 ps = readV3S32(&data[start+2]);
972 v3s32 ss = readV3S32(&data[start+2+12]);
973 s32 pitch_i = readS32(&data[start+2+12+12]);
974 s32 yaw_i = readS32(&data[start+2+12+12+4]);
975 /*dstream<<"Client: got "
976 <<"pitch_i="<<pitch_i
977 <<" yaw_i="<<yaw_i<<std::endl;*/
978 f32 pitch = (f32)pitch_i / 100.0;
979 f32 yaw = (f32)yaw_i / 100.0;
980 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
981 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
982 player->setPosition(position);
983 player->setSpeed(speed);
984 player->setPitch(pitch);
987 /*dstream<<"Client: player "<<peer_id
989 <<" yaw="<<yaw<<std::endl;*/
991 start += player_size;
995 else if(command == TOCLIENT_PLAYERINFO)
999 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1000 our_peer_id = m_con.GetPeerID();
1002 // Cancel if we don't have a peer id
1003 if(our_peer_id == PEER_ID_INEXISTENT){
1004 dout_client<<DTIME<<"TOCLIENT_PLAYERINFO cancelled: "
1005 "we have no peer id"
1010 //dstream<<DTIME<<"Client: Server reports players:"<<std::endl;
1013 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1015 u32 item_size = 2+PLAYERNAME_SIZE;
1016 u32 player_count = (datasize-2) / item_size;
1019 core::list<u16> players_alive;
1020 for(u32 i=0; i<player_count; i++)
1022 // Make sure the name ends in '\0'
1023 data[start+2+20-1] = 0;
1025 u16 peer_id = readU16(&data[start]);
1027 players_alive.push_back(peer_id);
1029 /*dstream<<DTIME<<"peer_id="<<peer_id
1030 <<" name="<<((char*)&data[start+2])<<std::endl;*/
1032 // Don't update the info of the local player
1033 if(peer_id == our_peer_id)
1039 Player *player = m_env.getPlayer(peer_id);
1041 // Create a player if it doesn't exist
1044 player = new RemotePlayer(
1045 m_device->getSceneManager()->getRootSceneNode(),
1048 player->peer_id = peer_id;
1049 m_env.addPlayer(player);
1050 dout_client<<DTIME<<"Client: Adding new player "
1051 <<peer_id<<std::endl;
1054 player->updateName((char*)&data[start+2]);
1060 Remove those players from the environment that
1061 weren't listed by the server.
1063 //dstream<<DTIME<<"Removing dead players"<<std::endl;
1064 core::list<Player*> players = m_env.getPlayers();
1065 core::list<Player*>::Iterator ip;
1066 for(ip=players.begin(); ip!=players.end(); ip++)
1068 // Ingore local player
1069 if((*ip)->isLocal())
1072 // Warn about a special case
1073 if((*ip)->peer_id == 0)
1075 dstream<<DTIME<<"WARNING: Client: Removing "
1076 "dead player with id=0"<<std::endl;
1079 bool is_alive = false;
1080 core::list<u16>::Iterator i;
1081 for(i=players_alive.begin(); i!=players_alive.end(); i++)
1083 if((*ip)->peer_id == *i)
1089 /*dstream<<DTIME<<"peer_id="<<((*ip)->peer_id)
1090 <<" is_alive="<<is_alive<<std::endl;*/
1093 dstream<<DTIME<<"Removing dead player "<<(*ip)->peer_id
1095 m_env.removePlayer((*ip)->peer_id);
1099 else if(command == TOCLIENT_SECTORMETA)
1101 dstream<<"Client received DEPRECATED TOCLIENT_SECTORMETA"<<std::endl;
1106 [3...] v2s16 pos + sector metadata
1111 //dstream<<"Client received TOCLIENT_SECTORMETA"<<std::endl;
1114 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1116 std::string datastring((char*)&data[2], datasize-2);
1117 std::istringstream is(datastring, std::ios_base::binary);
1121 is.read((char*)buf, 1);
1122 u16 sector_count = readU8(buf);
1124 //dstream<<"sector_count="<<sector_count<<std::endl;
1126 for(u16 i=0; i<sector_count; i++)
1129 is.read((char*)buf, 4);
1130 v2s16 pos = readV2S16(buf);
1131 /*dstream<<"Client: deserializing sector at "
1132 <<"("<<pos.X<<","<<pos.Y<<")"<<std::endl;*/
1134 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
1135 ((ClientMap&)m_env.getMap()).deSerializeSector(pos, is);
1140 else if(command == TOCLIENT_INVENTORY)
1145 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
1148 //TimeTaker t2("mutex locking", m_device);
1149 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1152 //TimeTaker t3("istringstream init", m_device);
1153 std::string datastring((char*)&data[2], datasize-2);
1154 std::istringstream is(datastring, std::ios_base::binary);
1157 //m_env.printPlayers(dstream);
1159 //TimeTaker t4("player get", m_device);
1160 Player *player = m_env.getLocalPlayer();
1161 assert(player != NULL);
1164 //TimeTaker t1("inventory.deSerialize()", m_device);
1165 player->inventory.deSerialize(is);
1168 m_inventory_updated = true;
1170 //dstream<<"Client got player inventory:"<<std::endl;
1171 //player->inventory.print(dstream);
1175 else if(command == TOCLIENT_OBJECTDATA)
1177 // Strip command word and create a stringstream
1178 std::string datastring((char*)&data[2], datasize-2);
1179 std::istringstream is(datastring, std::ios_base::binary);
1187 is.read((char*)buf, 2);
1188 u16 playercount = readU16(buf);
1190 for(u16 i=0; i<playercount; i++)
1192 is.read((char*)buf, 2);
1193 u16 peer_id = readU16(buf);
1194 is.read((char*)buf, 12);
1195 v3s32 p_i = readV3S32(buf);
1196 is.read((char*)buf, 12);
1197 v3s32 s_i = readV3S32(buf);
1198 is.read((char*)buf, 4);
1199 s32 pitch_i = readS32(buf);
1200 is.read((char*)buf, 4);
1201 s32 yaw_i = readS32(buf);
1203 Player *player = m_env.getPlayer(peer_id);
1205 // Skip if player doesn't exist
1211 // Skip if player is local player
1212 if(player->isLocal())
1217 f32 pitch = (f32)pitch_i / 100.0;
1218 f32 yaw = (f32)yaw_i / 100.0;
1219 v3f position((f32)p_i.X/100., (f32)p_i.Y/100., (f32)p_i.Z/100.);
1220 v3f speed((f32)s_i.X/100., (f32)s_i.Y/100., (f32)s_i.Z/100.);
1222 player->setPosition(position);
1223 player->setSpeed(speed);
1224 player->setPitch(pitch);
1225 player->setYaw(yaw);
1230 NOTE: Deprecated stuff
1233 // Read active block count
1234 u16 blockcount = readU16(is);
1235 if(blockcount != 0){
1236 dstream<<"WARNING: TOCLIENT_OBJECTDATA: blockcount != 0 "
1237 "not supported"<<std::endl;
1241 else if(command == TOCLIENT_TIME_OF_DAY)
1246 u16 time_of_day = readU16(&data[2]);
1247 time_of_day = time_of_day % 24000;
1248 //dstream<<"Client: time_of_day="<<time_of_day<<std::endl;
1256 m_env.setTimeOfDay(time_of_day);
1258 u32 dr = m_env.getDayNightRatio();
1260 dstream<<"Client: time_of_day="<<time_of_day
1266 else if(command == TOCLIENT_CHAT_MESSAGE)
1274 std::string datastring((char*)&data[2], datasize-2);
1275 std::istringstream is(datastring, std::ios_base::binary);
1278 is.read((char*)buf, 2);
1279 u16 len = readU16(buf);
1281 std::wstring message;
1282 for(u16 i=0; i<len; i++)
1284 is.read((char*)buf, 2);
1285 message += (wchar_t)readU16(buf);
1288 /*dstream<<"Client received chat message: "
1289 <<wide_to_narrow(message)<<std::endl;*/
1291 m_chat_queue.push_back(message);
1293 else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1295 //if(g_settings->getBool("enable_experimental"))
1299 u16 count of removed objects
1300 for all removed objects {
1303 u16 count of added objects
1304 for all added objects {
1307 u32 initialization data length
1308 string initialization data
1313 // Get all data except the command number
1314 std::string datastring((char*)&data[2], datasize-2);
1315 // Throw them in an istringstream
1316 std::istringstream is(datastring, std::ios_base::binary);
1320 // Read removed objects
1322 u16 removed_count = readU16((u8*)buf);
1323 for(u16 i=0; i<removed_count; i++)
1326 u16 id = readU16((u8*)buf);
1329 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1330 m_env.removeActiveObject(id);
1334 // Read added objects
1336 u16 added_count = readU16((u8*)buf);
1337 for(u16 i=0; i<added_count; i++)
1340 u16 id = readU16((u8*)buf);
1342 u8 type = readU8((u8*)buf);
1343 std::string data = deSerializeLongString(is);
1346 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1347 m_env.addActiveObject(id, type, data);
1352 else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1354 //if(g_settings->getBool("enable_experimental"))
1366 // Get all data except the command number
1367 std::string datastring((char*)&data[2], datasize-2);
1368 // Throw them in an istringstream
1369 std::istringstream is(datastring, std::ios_base::binary);
1371 while(is.eof() == false)
1375 u16 id = readU16((u8*)buf);
1379 u16 message_size = readU16((u8*)buf);
1380 std::string message;
1381 message.reserve(message_size);
1382 for(u16 i=0; i<message_size; i++)
1385 message.append(buf, 1);
1387 // Pass on to the environment
1389 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1390 m_env.processActiveObjectMessage(id, message);
1395 else if(command == TOCLIENT_HP)
1397 std::string datastring((char*)&data[2], datasize-2);
1398 std::istringstream is(datastring, std::ios_base::binary);
1399 Player *player = m_env.getLocalPlayer();
1400 assert(player != NULL);
1404 else if(command == TOCLIENT_MOVE_PLAYER)
1406 std::string datastring((char*)&data[2], datasize-2);
1407 std::istringstream is(datastring, std::ios_base::binary);
1408 Player *player = m_env.getLocalPlayer();
1409 assert(player != NULL);
1410 v3f pos = readV3F1000(is);
1411 f32 pitch = readF1000(is);
1412 f32 yaw = readF1000(is);
1413 player->setPosition(pos);
1414 /*player->setPitch(pitch);
1415 player->setYaw(yaw);*/
1417 dstream<<"Client got TOCLIENT_MOVE_PLAYER"
1418 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1424 Add to ClientEvent queue.
1425 This has to be sent to the main program because otherwise
1426 it would just force the pitch and yaw values to whatever
1427 the camera points to.
1430 event.type = CE_PLAYER_FORCE_MOVE;
1431 event.player_force_move.pitch = pitch;
1432 event.player_force_move.yaw = yaw;
1433 m_client_event_queue.push_back(event);
1435 // Ignore damage for a few seconds, so that the player doesn't
1436 // get damage from falling on ground
1437 m_ignore_damage_timer = 3.0;
1439 else if(command == TOCLIENT_PLAYERITEM)
1441 std::string datastring((char*)&data[2], datasize-2);
1442 std::istringstream is(datastring, std::ios_base::binary);
1444 u16 count = readU16(is);
1446 for (u16 i = 0; i < count; ++i) {
1447 u16 peer_id = readU16(is);
1448 Player *player = m_env.getPlayer(peer_id);
1452 dout_client<<DTIME<<"Client: ignoring player item "
1453 << deSerializeString(is)
1454 << " for non-existing peer id " << peer_id
1457 } else if (player->isLocal()) {
1458 dout_client<<DTIME<<"Client: ignoring player item "
1459 << deSerializeString(is)
1460 << " for local player" << std::endl;
1463 InventoryList *inv = player->inventory.getList("main");
1464 std::string itemstring(deSerializeString(is));
1465 if (itemstring.empty()) {
1468 <<"Client: empty player item for peer "
1469 << peer_id << std::endl;
1471 std::istringstream iss(itemstring);
1472 delete inv->changeItem(0, InventoryItem::deSerialize(iss));
1473 dout_client<<DTIME<<"Client: player item for peer " << peer_id << ": ";
1474 player->getWieldItem()->serialize(dout_client);
1475 dout_client<<std::endl;
1480 else if(command == TOCLIENT_DEATHSCREEN)
1482 std::string datastring((char*)&data[2], datasize-2);
1483 std::istringstream is(datastring, std::ios_base::binary);
1485 bool set_camera_point_target = readU8(is);
1486 v3f camera_point_target = readV3F1000(is);
1489 event.type = CE_DEATHSCREEN;
1490 event.deathscreen.set_camera_point_target = set_camera_point_target;
1491 event.deathscreen.camera_point_target_x = camera_point_target.X;
1492 event.deathscreen.camera_point_target_y = camera_point_target.Y;
1493 event.deathscreen.camera_point_target_z = camera_point_target.Z;
1494 m_client_event_queue.push_back(event);
1498 dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command "
1499 <<command<<std::endl;
1503 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1505 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1506 m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1509 void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
1510 v3s16 nodepos_oversurface, u16 item)
1512 if(connectedAndInitialized() == false){
1513 dout_client<<DTIME<<"Client::groundAction() "
1514 "cancelled (not connected)"
1523 [3] v3s16 nodepos_undersurface
1524 [9] v3s16 nodepos_abovesurface
1529 2: stop digging (all parameters ignored)
1530 3: digging completed
1532 u8 datasize = 2 + 1 + 6 + 6 + 2;
1533 SharedBuffer<u8> data(datasize);
1534 writeU16(&data[0], TOSERVER_GROUND_ACTION);
1535 writeU8(&data[2], action);
1536 writeV3S16(&data[3], nodepos_undersurface);
1537 writeV3S16(&data[9], nodepos_oversurface);
1538 writeU16(&data[15], item);
1539 Send(0, data, true);
1542 void Client::clickActiveObject(u8 button, u16 id, u16 item_i)
1544 if(connectedAndInitialized() == false){
1545 dout_client<<DTIME<<"Client::clickActiveObject() "
1546 "cancelled (not connected)"
1551 Player *player = m_env.getLocalPlayer();
1555 ClientActiveObject *obj = m_env.getActiveObject(id);
1558 ToolItem *titem = NULL;
1559 std::string toolname = "";
1561 InventoryList *mlist = player->inventory.getList("main");
1564 InventoryItem *item = mlist->getItem(item_i);
1565 if(item && (std::string)item->getName() == "ToolItem")
1567 titem = (ToolItem*)item;
1568 toolname = titem->getToolName();
1572 v3f playerpos = player->getPosition();
1573 v3f objpos = obj->getPosition();
1574 v3f dir = (objpos - playerpos).normalize();
1576 bool disable_send = obj->directReportPunch(toolname, dir);
1586 [2] u8 button (0=left, 1=right)
1590 u8 datasize = 2 + 1 + 6 + 2 + 2;
1591 SharedBuffer<u8> data(datasize);
1592 writeU16(&data[0], TOSERVER_CLICK_ACTIVEOBJECT);
1593 writeU8(&data[2], button);
1594 writeU16(&data[3], id);
1595 writeU16(&data[5], item_i);
1596 Send(0, data, true);
1599 void Client::sendSignNodeText(v3s16 p, std::string text)
1607 std::ostringstream os(std::ios_base::binary);
1611 writeU16(buf, TOSERVER_SIGNNODETEXT);
1612 os.write((char*)buf, 2);
1616 os.write((char*)buf, 6);
1618 u16 textlen = text.size();
1619 // Write text length
1620 writeS16(buf, textlen);
1621 os.write((char*)buf, 2);
1624 os.write((char*)text.c_str(), textlen);
1627 std::string s = os.str();
1628 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1630 Send(0, data, true);
1633 void Client::sendInventoryAction(InventoryAction *a)
1635 std::ostringstream os(std::ios_base::binary);
1639 writeU16(buf, TOSERVER_INVENTORY_ACTION);
1640 os.write((char*)buf, 2);
1645 std::string s = os.str();
1646 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1648 Send(0, data, true);
1651 void Client::sendChatMessage(const std::wstring &message)
1653 std::ostringstream os(std::ios_base::binary);
1657 writeU16(buf, TOSERVER_CHAT_MESSAGE);
1658 os.write((char*)buf, 2);
1661 writeU16(buf, message.size());
1662 os.write((char*)buf, 2);
1665 for(u32 i=0; i<message.size(); i++)
1669 os.write((char*)buf, 2);
1673 std::string s = os.str();
1674 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1676 Send(0, data, true);
1679 void Client::sendChangePassword(const std::wstring oldpassword,
1680 const std::wstring newpassword)
1682 Player *player = m_env.getLocalPlayer();
1686 std::string playername = player->getName();
1687 std::string oldpwd = translatePassword(playername, oldpassword);
1688 std::string newpwd = translatePassword(playername, newpassword);
1690 std::ostringstream os(std::ios_base::binary);
1691 u8 buf[2+PASSWORD_SIZE*2];
1693 [0] u16 TOSERVER_PASSWORD
1694 [2] u8[28] old password
1695 [30] u8[28] new password
1698 writeU16(buf, TOSERVER_PASSWORD);
1699 for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1701 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1702 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1704 buf[2+PASSWORD_SIZE-1] = 0;
1705 buf[30+PASSWORD_SIZE-1] = 0;
1706 os.write((char*)buf, 2+PASSWORD_SIZE*2);
1709 std::string s = os.str();
1710 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1712 Send(0, data, true);
1716 void Client::sendDamage(u8 damage)
1718 DSTACK(__FUNCTION_NAME);
1719 std::ostringstream os(std::ios_base::binary);
1721 writeU16(os, TOSERVER_DAMAGE);
1722 writeU8(os, damage);
1725 std::string s = os.str();
1726 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1728 Send(0, data, true);
1731 void Client::sendRespawn()
1733 DSTACK(__FUNCTION_NAME);
1734 std::ostringstream os(std::ios_base::binary);
1736 writeU16(os, TOSERVER_RESPAWN);
1739 std::string s = os.str();
1740 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1742 Send(0, data, true);
1745 void Client::sendPlayerPos()
1747 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1749 Player *myplayer = m_env.getLocalPlayer();
1750 if(myplayer == NULL)
1755 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1756 our_peer_id = m_con.GetPeerID();
1759 // Set peer id if not set already
1760 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1761 myplayer->peer_id = our_peer_id;
1762 // Check that an existing peer_id is the same as the connection's
1763 assert(myplayer->peer_id == our_peer_id);
1765 v3f pf = myplayer->getPosition();
1766 v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1767 v3f sf = myplayer->getSpeed();
1768 v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1769 s32 pitch = myplayer->getPitch() * 100;
1770 s32 yaw = myplayer->getYaw() * 100;
1775 [2] v3s32 position*100
1776 [2+12] v3s32 speed*100
1777 [2+12+12] s32 pitch*100
1778 [2+12+12+4] s32 yaw*100
1781 SharedBuffer<u8> data(2+12+12+4+4);
1782 writeU16(&data[0], TOSERVER_PLAYERPOS);
1783 writeV3S32(&data[2], position);
1784 writeV3S32(&data[2+12], speed);
1785 writeS32(&data[2+12+12], pitch);
1786 writeS32(&data[2+12+12+4], yaw);
1788 // Send as unreliable
1789 Send(0, data, false);
1792 void Client::sendPlayerItem(u16 item)
1794 Player *myplayer = m_env.getLocalPlayer();
1795 if(myplayer == NULL)
1798 u16 our_peer_id = m_con.GetPeerID();
1800 // Set peer id if not set already
1801 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1802 myplayer->peer_id = our_peer_id;
1803 // Check that an existing peer_id is the same as the connection's
1804 assert(myplayer->peer_id == our_peer_id);
1806 SharedBuffer<u8> data(2+2);
1807 writeU16(&data[0], TOSERVER_PLAYERITEM);
1808 writeU16(&data[2], item);
1811 Send(0, data, true);
1814 void Client::removeNode(v3s16 p)
1816 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1818 core::map<v3s16, MapBlock*> modified_blocks;
1822 //TimeTaker t("removeNodeAndUpdate", m_device);
1823 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1825 catch(InvalidPositionException &e)
1829 for(core::map<v3s16, MapBlock * >::Iterator
1830 i = modified_blocks.getIterator();
1831 i.atEnd() == false; i++)
1833 v3s16 p = i.getNode()->getKey();
1834 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1835 addUpdateMeshTaskWithEdge(p);
1839 void Client::addNode(v3s16 p, MapNode n)
1841 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1843 TimeTaker timer1("Client::addNode()");
1845 core::map<v3s16, MapBlock*> modified_blocks;
1849 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1850 std::string st = std::string("");
1851 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st);
1853 catch(InvalidPositionException &e)
1856 //TimeTaker timer2("Client::addNode(): updateMeshes");
1858 for(core::map<v3s16, MapBlock * >::Iterator
1859 i = modified_blocks.getIterator();
1860 i.atEnd() == false; i++)
1862 v3s16 p = i.getNode()->getKey();
1863 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1864 addUpdateMeshTaskWithEdge(p);
1868 void Client::updateCamera(v3f pos, v3f dir, f32 fov)
1870 m_env.getClientMap().updateCamera(pos, dir, fov);
1873 void Client::renderPostFx()
1875 m_env.getClientMap().renderPostFx();
1878 MapNode Client::getNode(v3s16 p)
1880 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1881 return m_env.getMap().getNode(p);
1884 NodeMetadata* Client::getNodeMetadata(v3s16 p)
1886 return m_env.getMap().getNodeMetadata(p);
1889 LocalPlayer* Client::getLocalPlayer()
1891 return m_env.getLocalPlayer();
1894 void Client::setPlayerControl(PlayerControl &control)
1896 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1897 LocalPlayer *player = m_env.getLocalPlayer();
1898 assert(player != NULL);
1899 player->control = control;
1902 void Client::selectPlayerItem(u16 item)
1904 LocalPlayer *player = m_env.getLocalPlayer();
1905 assert(player != NULL);
1907 player->wieldItem(item);
1909 sendPlayerItem(item);
1912 // Returns true if the inventory of the local player has been
1913 // updated from the server. If it is true, it is set to false.
1914 bool Client::getLocalInventoryUpdated()
1916 // m_inventory_updated is behind envlock
1917 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1918 bool updated = m_inventory_updated;
1919 m_inventory_updated = false;
1923 // Copies the inventory of the local player to parameter
1924 void Client::getLocalInventory(Inventory &dst)
1926 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1927 Player *player = m_env.getLocalPlayer();
1928 assert(player != NULL);
1929 dst = player->inventory;
1932 InventoryContext *Client::getInventoryContext()
1934 return &m_inventory_context;
1937 Inventory* Client::getInventory(InventoryContext *c, std::string id)
1939 if(id == "current_player")
1941 assert(c->current_player);
1942 return &(c->current_player->inventory);
1946 std::string id0 = fn.next(":");
1948 if(id0 == "nodemeta")
1951 p.X = stoi(fn.next(","));
1952 p.Y = stoi(fn.next(","));
1953 p.Z = stoi(fn.next(","));
1954 NodeMetadata* meta = getNodeMetadata(p);
1956 return meta->getInventory();
1957 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
1958 <<"no metadata found"<<std::endl;
1962 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
1965 void Client::inventoryAction(InventoryAction *a)
1967 sendInventoryAction(a);
1970 ClientActiveObject * Client::getSelectedActiveObject(
1972 v3f from_pos_f_on_map,
1973 core::line3d<f32> shootline_on_map
1976 core::array<DistanceSortedActiveObject> objects;
1978 m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
1980 //dstream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
1983 // After this, the closest object is the first in the array.
1986 for(u32 i=0; i<objects.size(); i++)
1988 ClientActiveObject *obj = objects[i].obj;
1990 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
1991 if(selection_box == NULL)
1994 v3f pos = obj->getPosition();
1996 core::aabbox3d<f32> offsetted_box(
1997 selection_box->MinEdge + pos,
1998 selection_box->MaxEdge + pos
2001 if(offsetted_box.intersectsWithLine(shootline_on_map))
2003 //dstream<<"Returning selected object"<<std::endl;
2008 //dstream<<"No object selected; returning NULL."<<std::endl;
2012 void Client::printDebugInfo(std::ostream &os)
2014 //JMutexAutoLock lock1(m_fetchblock_mutex);
2015 /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2017 os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2018 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2019 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2023 u32 Client::getDayNightRatio()
2025 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2026 return m_env.getDayNightRatio();
2031 Player *player = m_env.getLocalPlayer();
2032 assert(player != NULL);
2036 void Client::setTempMod(v3s16 p, NodeMod mod)
2038 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2039 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2041 core::map<v3s16, MapBlock*> affected_blocks;
2042 ((ClientMap&)m_env.getMap()).setTempMod(p, mod,
2045 for(core::map<v3s16, MapBlock*>::Iterator
2046 i = affected_blocks.getIterator();
2047 i.atEnd() == false; i++)
2049 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2053 void Client::clearTempMod(v3s16 p)
2055 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2056 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2058 core::map<v3s16, MapBlock*> affected_blocks;
2059 ((ClientMap&)m_env.getMap()).clearTempMod(p,
2062 for(core::map<v3s16, MapBlock*>::Iterator
2063 i = affected_blocks.getIterator();
2064 i.atEnd() == false; i++)
2066 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2070 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
2072 /*dstream<<"Client::addUpdateMeshTask(): "
2073 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2076 MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2081 Create a task to update the mesh of the block
2084 MeshMakeData *data = new MeshMakeData;
2087 //TimeTaker timer("data fill");
2089 // Debug: 1-6ms, avg=2ms
2090 data->fill(getDayNightRatio(), b);
2094 //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2096 // Add task to queue
2097 m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server);
2099 /*dstream<<"Mesh update input queue size is "
2100 <<m_mesh_update_thread.m_queue_in.size()
2104 // Temporary test: make mesh directly in here
2106 //TimeTaker timer("make mesh");
2108 scene::SMesh *mesh_new = NULL;
2109 mesh_new = makeMapBlockMesh(data);
2110 b->replaceMesh(mesh_new);
2116 Mark mesh as non-expired at this point so that it can already
2117 be marked as expired again if the data changes
2119 b->setMeshExpired(false);
2122 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
2126 dstream<<"Client::addUpdateMeshTaskWithEdge(): "
2127 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2132 v3s16 p = blockpos + v3s16(0,0,0);
2133 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2134 addUpdateMeshTask(p, ack_to_server);
2136 catch(InvalidPositionException &e){}
2139 v3s16 p = blockpos + v3s16(-1,0,0);
2140 addUpdateMeshTask(p);
2142 catch(InvalidPositionException &e){}
2144 v3s16 p = blockpos + v3s16(0,-1,0);
2145 addUpdateMeshTask(p);
2147 catch(InvalidPositionException &e){}
2149 v3s16 p = blockpos + v3s16(0,0,-1);
2150 addUpdateMeshTask(p);
2152 catch(InvalidPositionException &e){}
2155 ClientEvent Client::getClientEvent()
2157 if(m_client_event_queue.size() == 0)
2160 event.type = CE_NONE;
2163 return m_client_event_queue.pop_front();