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"
29 void * MeshUpdateThread::Thread()
33 DSTACK(__FUNCTION_NAME);
35 BEGIN_DEBUG_EXCEPTION_HANDLER
39 QueuedMeshUpdate *q = m_queue_in.pop();
46 scene::SMesh *mesh_new = NULL;
47 mesh_new = makeMapBlockMesh(q->data);
52 r.ack_block_to_server = q->ack_block_to_server;
54 /*dstream<<"MeshUpdateThread: Processed "
55 <<"("<<q->p.X<<","<<q->p.Y<<","<<q->p.Z<<")"
58 m_queue_out.push_back(r);
63 END_DEBUG_EXCEPTION_HANDLER
69 IrrlichtDevice *device,
70 const char *playername,
71 MapDrawControl &control):
72 m_mesh_update_thread(),
74 new ClientMap(this, control,
75 device->getSceneManager()->getRootSceneNode(),
76 device->getSceneManager(), 666),
77 device->getSceneManager()
79 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
81 camera_position(0,0,0),
82 camera_direction(0,0,1),
83 m_server_ser_ver(SER_FMT_VER_INVALID),
84 m_inventory_updated(false),
88 m_packetcounter_timer = 0.0;
89 m_delete_unused_sectors_timer = 0.0;
90 m_connection_reinit_timer = 0.0;
91 m_avg_rtt_timer = 0.0;
92 m_playerpos_send_timer = 0.0;
97 m_mesh_update_thread.Start();
103 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
105 Player *player = new LocalPlayer();
107 player->updateName(playername);
109 m_env.addPlayer(player);
111 // Initialize player in the inventory context
112 m_inventory_context.current_player = player;
119 //JMutexAutoLock conlock(m_con_mutex); //bulk comment-out
123 m_mesh_update_thread.setRun(false);
124 while(m_mesh_update_thread.IsRunning())
128 void Client::connect(Address address)
130 DSTACK(__FUNCTION_NAME);
131 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
132 m_con.setTimeoutMs(0);
133 m_con.Connect(address);
136 bool Client::connectedAndInitialized()
138 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
140 if(m_con.Connected() == false)
143 if(m_server_ser_ver == SER_FMT_VER_INVALID)
149 void Client::step(float dtime)
151 DSTACK(__FUNCTION_NAME);
158 //dstream<<"Client steps "<<dtime<<std::endl;
161 //TimeTaker timer("ReceiveAll()", m_device);
167 //TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device);
169 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
170 m_con.RunTimeouts(dtime);
177 float &counter = m_packetcounter_timer;
183 dout_client<<"Client packetcounter (20s):"<<std::endl;
184 m_packetcounter.print(dout_client);
185 m_packetcounter.clear();
191 Delete unused sectors
193 NOTE: This jams the game for a while because deleting sectors
197 float &counter = m_delete_unused_sectors_timer;
205 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
207 core::list<v3s16> deleted_blocks;
209 float delete_unused_sectors_timeout =
210 g_settings.getFloat("client_delete_unused_sectors_timeout");
212 // Delete sector blocks
213 /*u32 num = m_env.getMap().deleteUnusedSectors
214 (delete_unused_sectors_timeout,
215 true, &deleted_blocks);*/
217 // Delete whole sectors
218 u32 num = m_env.getMap().deleteUnusedSectors
219 (delete_unused_sectors_timeout,
220 false, &deleted_blocks);
224 /*dstream<<DTIME<<"Client: Deleted blocks of "<<num
225 <<" unused sectors"<<std::endl;*/
226 dstream<<DTIME<<"Client: Deleted "<<num
227 <<" unused sectors"<<std::endl;
233 // Env is locked so con can be locked.
234 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
236 core::list<v3s16>::Iterator i = deleted_blocks.begin();
237 core::list<v3s16> sendlist;
240 if(sendlist.size() == 255 || i == deleted_blocks.end())
242 if(sendlist.size() == 0)
251 u32 replysize = 2+1+6*sendlist.size();
252 SharedBuffer<u8> reply(replysize);
253 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
254 reply[2] = sendlist.size();
256 for(core::list<v3s16>::Iterator
257 j = sendlist.begin();
258 j != sendlist.end(); j++)
260 writeV3S16(&reply[2+1+6*k], *j);
263 m_con.Send(PEER_ID_SERVER, 1, reply, true);
265 if(i == deleted_blocks.end())
271 sendlist.push_back(*i);
278 bool connected = connectedAndInitialized();
280 if(connected == false)
282 float &counter = m_connection_reinit_timer;
288 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
290 Player *myplayer = m_env.getLocalPlayer();
291 assert(myplayer != NULL);
293 // Send TOSERVER_INIT
294 // [0] u16 TOSERVER_INIT
295 // [2] u8 SER_FMT_VER_HIGHEST
296 // [3] u8[20] player_name
297 SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE);
298 writeU16(&data[0], TOSERVER_INIT);
299 writeU8(&data[2], SER_FMT_VER_HIGHEST);
300 memset((char*)&data[3], 0, PLAYERNAME_SIZE);
301 snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
302 // Send as unreliable
303 Send(0, data, false);
306 // Not connected, return
311 Do stuff if connected
316 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
318 // Control local player (0ms)
319 LocalPlayer *player = m_env.getLocalPlayer();
320 assert(player != NULL);
321 player->applyControl(dtime);
323 //TimeTaker envtimer("env step", m_device);
327 // Step active blocks
328 for(core::map<v3s16, bool>::Iterator
329 i = m_active_blocks.getIterator();
330 i.atEnd() == false; i++)
332 v3s16 p = i.getNode()->getKey();
334 MapBlock *block = NULL;
337 block = m_env.getMap().getBlockNoCreate(p);
338 block->stepObjects(dtime, false, m_env.getDayNightRatio());
340 catch(InvalidPositionException &e)
347 float &counter = m_avg_rtt_timer;
352 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
353 // connectedAndInitialized() is true, peer exists.
354 con::Peer *peer = m_con.GetPeer(PEER_ID_SERVER);
355 dstream<<DTIME<<"Client: avg_rtt="<<peer->avg_rtt<<std::endl;
359 float &counter = m_playerpos_send_timer;
369 Replace updated meshes
372 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
374 //TimeTaker timer("** Processing mesh update result queue");
377 /*dstream<<"Mesh update result queue size is "
378 <<m_mesh_update_thread.m_queue_out.size()
381 while(m_mesh_update_thread.m_queue_out.size() > 0)
383 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
384 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
387 block->replaceMesh(r.mesh);
389 if(r.ack_block_to_server)
401 u32 replysize = 2+1+6;
402 SharedBuffer<u8> reply(replysize);
403 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
405 writeV3S16(&reply[3], r.p);
407 m_con.Send(PEER_ID_SERVER, 1, reply, true);
413 // Virtual methods from con::PeerHandler
414 void Client::peerAdded(con::Peer *peer)
416 derr_client<<"Client::peerAdded(): peer->id="
417 <<peer->id<<std::endl;
419 void Client::deletingPeer(con::Peer *peer, bool timeout)
421 derr_client<<"Client::deletingPeer(): "
422 "Server Peer is getting deleted "
423 <<"(timeout="<<timeout<<")"<<std::endl;
426 void Client::ReceiveAll()
428 DSTACK(__FUNCTION_NAME);
434 catch(con::NoIncomingDataException &e)
438 catch(con::InvalidIncomingDataException &e)
440 dout_client<<DTIME<<"Client::ReceiveAll(): "
441 "InvalidIncomingDataException: what()="
442 <<e.what()<<std::endl;
447 void Client::Receive()
449 DSTACK(__FUNCTION_NAME);
450 u32 data_maxsize = 10000;
451 Buffer<u8> data(data_maxsize);
455 //TimeTaker t1("con mutex and receive", m_device);
456 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
457 datasize = m_con.Receive(sender_peer_id, *data, data_maxsize);
459 //TimeTaker t1("ProcessData", m_device);
460 ProcessData(*data, datasize, sender_peer_id);
464 sender_peer_id given to this shall be quaranteed to be a valid peer
466 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
468 DSTACK(__FUNCTION_NAME);
470 // Ignore packets that don't even fit a command
473 m_packetcounter.add(60000);
477 ToClientCommand command = (ToClientCommand)readU16(&data[0]);
479 //dstream<<"Client: received command="<<command<<std::endl;
480 m_packetcounter.add((u16)command);
483 If this check is removed, be sure to change the queue
484 system to know the ids
486 if(sender_peer_id != PEER_ID_SERVER)
488 dout_client<<DTIME<<"Client::ProcessData(): Discarding data not "
489 "coming from server: peer_id="<<sender_peer_id
496 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
497 // All data is coming from the server
498 // PeerNotFoundException is handled by caller.
499 peer = m_con.GetPeer(PEER_ID_SERVER);
502 u8 ser_version = m_server_ser_ver;
504 //dstream<<"Client received command="<<(int)command<<std::endl;
506 // Execute fast commands straight away
508 if(command == TOCLIENT_INIT)
513 u8 deployed = data[2];
515 dout_client<<DTIME<<"Client: TOCLIENT_INIT received with "
516 "deployed="<<((int)deployed&0xff)<<std::endl;
518 if(deployed < SER_FMT_VER_LOWEST
519 || deployed > SER_FMT_VER_HIGHEST)
521 derr_client<<DTIME<<"Client: TOCLIENT_INIT: Server sent "
522 <<"unsupported ser_fmt_ver"<<std::endl;
526 m_server_ser_ver = deployed;
528 // Get player position
529 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
530 if(datasize >= 2+1+6)
531 playerpos_s16 = readV3S16(&data[2+1]);
532 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
535 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
537 // Set player position
538 Player *player = m_env.getLocalPlayer();
539 assert(player != NULL);
540 player->setPosition(playerpos_f);
543 if(datasize >= 2+1+6+8)
546 m_map_seed = readU64(&data[2+1+6]);
547 dstream<<"Client: received map seed: "<<m_map_seed<<std::endl;
552 SharedBuffer<u8> reply(replysize);
553 writeU16(&reply[0], TOSERVER_INIT2);
555 m_con.Send(PEER_ID_SERVER, 1, reply, true);
560 if(ser_version == SER_FMT_VER_INVALID)
562 dout_client<<DTIME<<"WARNING: Client: Server serialization"
563 " format invalid or not initialized."
564 " Skipping incoming command="<<command<<std::endl;
568 // Just here to avoid putting the two if's together when
569 // making some copypasta
572 if(command == TOCLIENT_REMOVENODE)
577 p.X = readS16(&data[2]);
578 p.Y = readS16(&data[4]);
579 p.Z = readS16(&data[6]);
581 //TimeTaker t1("TOCLIENT_REMOVENODE", g_device);
583 // This will clear the cracking animation after digging
584 ((ClientMap&)m_env.getMap()).clearTempMod(p);
588 else if(command == TOCLIENT_ADDNODE)
590 if(datasize < 8 + MapNode::serializedLength(ser_version))
594 p.X = readS16(&data[2]);
595 p.Y = readS16(&data[4]);
596 p.Z = readS16(&data[6]);
598 //TimeTaker t1("TOCLIENT_ADDNODE", g_device);
601 n.deSerialize(&data[8], ser_version);
605 else if(command == TOCLIENT_BLOCKDATA)
607 // Ignore too small packet
612 p.X = readS16(&data[2]);
613 p.Y = readS16(&data[4]);
614 p.Z = readS16(&data[6]);
616 /*dout_client<<DTIME<<"Client: Thread: BLOCKDATA for ("
617 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
618 /*dstream<<DTIME<<"Client: Thread: BLOCKDATA for ("
619 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
621 std::string datastring((char*)&data[8], datasize-8);
622 std::istringstream istr(datastring, std::ios_base::binary);
628 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
631 sector = m_env.getMap().emergeSector(p2d);
633 v2s16 sp = sector->getPos();
636 dstream<<"ERROR: Got sector with getPos()="
637 <<"("<<sp.X<<","<<sp.Y<<"), tried to get"
638 <<"("<<p2d.X<<","<<p2d.Y<<")"<<std::endl;
642 //assert(sector->getPos() == p2d);
644 //TimeTaker timer("MapBlock deSerialize");
648 block = sector->getBlockNoCreate(p.Y);
650 Update an existing block
652 //dstream<<"Updating"<<std::endl;
653 block->deSerialize(istr, ser_version);
654 //block->setChangedFlag();
656 catch(InvalidPositionException &e)
661 //dstream<<"Creating new"<<std::endl;
662 block = new MapBlock(&m_env.getMap(), p);
663 block->deSerialize(istr, ser_version);
664 sector->insertBlock(block);
665 //block->setChangedFlag();
669 mod.type = NODEMOD_CHANGECONTENT;
670 mod.param = CONTENT_MESE;
671 block->setTempMod(v3s16(8,10,8), mod);
672 block->setTempMod(v3s16(8,9,8), mod);
673 block->setTempMod(v3s16(8,8,8), mod);
674 block->setTempMod(v3s16(8,7,8), mod);
675 block->setTempMod(v3s16(8,6,8), mod);*/
679 Well, this is a dumb way to do it, they should just
680 be drawn as separate objects. But the looks of them
681 can be tested this way.
686 mod.type = NODEMOD_CHANGECONTENT;
687 mod.param = CONTENT_CLOUD;
690 for(p2.X=3; p2.X<=13; p2.X++)
691 for(p2.Z=3; p2.Z<=13; p2.Z++)
693 block->setTempMod(p2, mod);
711 u32 replysize = 2+1+6;
712 SharedBuffer<u8> reply(replysize);
713 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
715 writeV3S16(&reply[3], p);
717 m_con.Send(PEER_ID_SERVER, 1, reply, true);
721 Update Mesh of this block and blocks at x-, y- and z-.
722 Environment should not be locked as it interlocks with the
723 main thread, from which is will want to retrieve textures.
726 //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
728 addUpdateMeshTaskWithEdge(p, true);
730 else if(command == TOCLIENT_PLAYERPOS)
732 dstream<<"WARNING: Received deprecated TOCLIENT_PLAYERPOS"
736 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
737 our_peer_id = m_con.GetPeerID();
739 // Cancel if we don't have a peer id
740 if(our_peer_id == PEER_ID_INEXISTENT){
741 dout_client<<DTIME<<"TOCLIENT_PLAYERPOS cancelled: "
748 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
750 u32 player_size = 2+12+12+4+4;
752 u32 player_count = (datasize-2) / player_size;
754 for(u32 i=0; i<player_count; i++)
756 u16 peer_id = readU16(&data[start]);
758 Player *player = m_env.getPlayer(peer_id);
760 // Skip if player doesn't exist
763 start += player_size;
767 // Skip if player is local player
768 if(player->isLocal())
770 start += player_size;
774 v3s32 ps = readV3S32(&data[start+2]);
775 v3s32 ss = readV3S32(&data[start+2+12]);
776 s32 pitch_i = readS32(&data[start+2+12+12]);
777 s32 yaw_i = readS32(&data[start+2+12+12+4]);
778 /*dstream<<"Client: got "
779 <<"pitch_i="<<pitch_i
780 <<" yaw_i="<<yaw_i<<std::endl;*/
781 f32 pitch = (f32)pitch_i / 100.0;
782 f32 yaw = (f32)yaw_i / 100.0;
783 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
784 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
785 player->setPosition(position);
786 player->setSpeed(speed);
787 player->setPitch(pitch);
790 /*dstream<<"Client: player "<<peer_id
792 <<" yaw="<<yaw<<std::endl;*/
794 start += player_size;
798 else if(command == TOCLIENT_PLAYERINFO)
802 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
803 our_peer_id = m_con.GetPeerID();
805 // Cancel if we don't have a peer id
806 if(our_peer_id == PEER_ID_INEXISTENT){
807 dout_client<<DTIME<<"TOCLIENT_PLAYERINFO cancelled: "
813 //dstream<<DTIME<<"Client: Server reports players:"<<std::endl;
816 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
818 u32 item_size = 2+PLAYERNAME_SIZE;
819 u32 player_count = (datasize-2) / item_size;
822 core::list<u16> players_alive;
823 for(u32 i=0; i<player_count; i++)
825 // Make sure the name ends in '\0'
826 data[start+2+20-1] = 0;
828 u16 peer_id = readU16(&data[start]);
830 players_alive.push_back(peer_id);
832 /*dstream<<DTIME<<"peer_id="<<peer_id
833 <<" name="<<((char*)&data[start+2])<<std::endl;*/
835 // Don't update the info of the local player
836 if(peer_id == our_peer_id)
842 Player *player = m_env.getPlayer(peer_id);
844 // Create a player if it doesn't exist
847 player = new RemotePlayer(
848 m_device->getSceneManager()->getRootSceneNode(),
851 player->peer_id = peer_id;
852 m_env.addPlayer(player);
853 dout_client<<DTIME<<"Client: Adding new player "
854 <<peer_id<<std::endl;
857 player->updateName((char*)&data[start+2]);
863 Remove those players from the environment that
864 weren't listed by the server.
866 //dstream<<DTIME<<"Removing dead players"<<std::endl;
867 core::list<Player*> players = m_env.getPlayers();
868 core::list<Player*>::Iterator ip;
869 for(ip=players.begin(); ip!=players.end(); ip++)
871 // Ingore local player
875 // Warn about a special case
876 if((*ip)->peer_id == 0)
878 dstream<<DTIME<<"WARNING: Client: Removing "
879 "dead player with id=0"<<std::endl;
882 bool is_alive = false;
883 core::list<u16>::Iterator i;
884 for(i=players_alive.begin(); i!=players_alive.end(); i++)
886 if((*ip)->peer_id == *i)
892 /*dstream<<DTIME<<"peer_id="<<((*ip)->peer_id)
893 <<" is_alive="<<is_alive<<std::endl;*/
896 dstream<<DTIME<<"Removing dead player "<<(*ip)->peer_id
898 m_env.removePlayer((*ip)->peer_id);
902 else if(command == TOCLIENT_SECTORMETA)
907 [3...] v2s16 pos + sector metadata
912 //dstream<<"Client received TOCLIENT_SECTORMETA"<<std::endl;
915 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
917 std::string datastring((char*)&data[2], datasize-2);
918 std::istringstream is(datastring, std::ios_base::binary);
922 is.read((char*)buf, 1);
923 u16 sector_count = readU8(buf);
925 //dstream<<"sector_count="<<sector_count<<std::endl;
927 for(u16 i=0; i<sector_count; i++)
930 is.read((char*)buf, 4);
931 v2s16 pos = readV2S16(buf);
932 /*dstream<<"Client: deserializing sector at "
933 <<"("<<pos.X<<","<<pos.Y<<")"<<std::endl;*/
935 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
936 ((ClientMap&)m_env.getMap()).deSerializeSector(pos, is);
940 else if(command == TOCLIENT_INVENTORY)
945 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
948 //TimeTaker t2("mutex locking", m_device);
949 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
952 //TimeTaker t3("istringstream init", m_device);
953 std::string datastring((char*)&data[2], datasize-2);
954 std::istringstream is(datastring, std::ios_base::binary);
957 //m_env.printPlayers(dstream);
959 //TimeTaker t4("player get", m_device);
960 Player *player = m_env.getLocalPlayer();
961 assert(player != NULL);
964 //TimeTaker t1("inventory.deSerialize()", m_device);
965 player->inventory.deSerialize(is);
968 m_inventory_updated = true;
970 //dstream<<"Client got player inventory:"<<std::endl;
971 //player->inventory.print(dstream);
975 else if(command == TOCLIENT_OBJECTDATA)
978 // Strip command word and create a stringstream
979 std::string datastring((char*)&data[2], datasize-2);
980 std::istringstream is(datastring, std::ios_base::binary);
984 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
992 is.read((char*)buf, 2);
993 u16 playercount = readU16(buf);
995 for(u16 i=0; i<playercount; i++)
997 is.read((char*)buf, 2);
998 u16 peer_id = readU16(buf);
999 is.read((char*)buf, 12);
1000 v3s32 p_i = readV3S32(buf);
1001 is.read((char*)buf, 12);
1002 v3s32 s_i = readV3S32(buf);
1003 is.read((char*)buf, 4);
1004 s32 pitch_i = readS32(buf);
1005 is.read((char*)buf, 4);
1006 s32 yaw_i = readS32(buf);
1008 Player *player = m_env.getPlayer(peer_id);
1010 // Skip if player doesn't exist
1016 // Skip if player is local player
1017 if(player->isLocal())
1022 f32 pitch = (f32)pitch_i / 100.0;
1023 f32 yaw = (f32)yaw_i / 100.0;
1024 v3f position((f32)p_i.X/100., (f32)p_i.Y/100., (f32)p_i.Z/100.);
1025 v3f speed((f32)s_i.X/100., (f32)s_i.Y/100., (f32)s_i.Z/100.);
1027 player->setPosition(position);
1028 player->setSpeed(speed);
1029 player->setPitch(pitch);
1030 player->setYaw(yaw);
1037 // Read active block count
1038 is.read((char*)buf, 2);
1039 u16 blockcount = readU16(buf);
1041 // Initialize delete queue with all active blocks
1042 core::map<v3s16, bool> abs_to_delete;
1043 for(core::map<v3s16, bool>::Iterator
1044 i = m_active_blocks.getIterator();
1045 i.atEnd() == false; i++)
1047 v3s16 p = i.getNode()->getKey();
1048 /*dstream<<"adding "
1049 <<"("<<p.x<<","<<p.y<<","<<p.z<<") "
1050 <<" to abs_to_delete"
1052 abs_to_delete.insert(p, true);
1055 /*dstream<<"Initial delete queue size: "<<abs_to_delete.size()
1058 for(u16 i=0; i<blockcount; i++)
1061 is.read((char*)buf, 6);
1062 v3s16 p = readV3S16(buf);
1063 // Get block from somewhere
1064 MapBlock *block = NULL;
1066 block = m_env.getMap().getBlockNoCreate(p);
1068 catch(InvalidPositionException &e)
1070 //TODO: Create a dummy block?
1074 dstream<<"WARNING: "
1075 <<"Could not get block at blockpos "
1076 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
1077 <<"in TOCLIENT_OBJECTDATA. Ignoring "
1078 <<"following block object data."
1083 /*dstream<<"Client updating objects for block "
1084 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1087 // Insert to active block list
1088 m_active_blocks.insert(p, true);
1090 // Remove from deletion queue
1091 if(abs_to_delete.find(p) != NULL)
1092 abs_to_delete.remove(p);
1095 Update objects of block
1097 NOTE: Be sure this is done in the main thread.
1099 block->updateObjects(is, m_server_ser_ver,
1100 m_device->getSceneManager(), m_env.getDayNightRatio());
1103 /*dstream<<"Final delete queue size: "<<abs_to_delete.size()
1106 // Delete objects of blocks in delete queue
1107 for(core::map<v3s16, bool>::Iterator
1108 i = abs_to_delete.getIterator();
1109 i.atEnd() == false; i++)
1111 v3s16 p = i.getNode()->getKey();
1114 MapBlock *block = m_env.getMap().getBlockNoCreate(p);
1117 block->clearObjects();
1118 // Remove from active blocks list
1119 m_active_blocks.remove(p);
1121 catch(InvalidPositionException &e)
1123 dstream<<"WARNAING: Client: "
1124 <<"Couldn't clear objects of active->inactive"
1126 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1127 <<" because block was not found"
1135 else if(command == TOCLIENT_TIME_OF_DAY)
1140 u16 time = readU16(&data[2]);
1141 time = time % 24000;
1142 m_time_of_day = time;
1143 //dstream<<"Client: time="<<time<<std::endl;
1153 u32 dr = time_to_daynight_ratio(m_time_of_day);
1155 dstream<<"Client: time_of_day="<<m_time_of_day
1159 if(dr != m_env.getDayNightRatio())
1161 dout_client<<DTIME<<"Client: changing day-night ratio"<<std::endl;
1162 m_env.setDayNightRatio(dr);
1163 m_env.expireMeshes(true);
1168 else if(command == TOCLIENT_CHAT_MESSAGE)
1176 std::string datastring((char*)&data[2], datasize-2);
1177 std::istringstream is(datastring, std::ios_base::binary);
1180 is.read((char*)buf, 2);
1181 u16 len = readU16(buf);
1183 std::wstring message;
1184 for(u16 i=0; i<len; i++)
1186 is.read((char*)buf, 2);
1187 message += (wchar_t)readU16(buf);
1190 /*dstream<<"Client received chat message: "
1191 <<wide_to_narrow(message)<<std::endl;*/
1193 m_chat_queue.push_back(message);
1195 else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1197 //if(g_settings.getBool("enable_experimental"))
1201 u16 count of removed objects
1202 for all removed objects {
1205 u16 count of added objects
1206 for all added objects {
1209 u16 initialization data length
1210 string initialization data
1215 // Get all data except the command number
1216 std::string datastring((char*)&data[2], datasize-2);
1217 // Throw them in an istringstream
1218 std::istringstream is(datastring, std::ios_base::binary);
1222 // Read removed objects
1224 u16 removed_count = readU16((u8*)buf);
1225 for(u16 i=0; i<removed_count; i++)
1228 u16 id = readU16((u8*)buf);
1231 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1232 m_env.removeActiveObject(id);
1236 // Read added objects
1238 u16 added_count = readU16((u8*)buf);
1239 for(u16 i=0; i<added_count; i++)
1242 u16 id = readU16((u8*)buf);
1244 u8 type = readU8((u8*)buf);
1245 std::string data = deSerializeLongString(is);
1248 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1249 m_env.addActiveObject(id, type, data);
1254 else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1256 //if(g_settings.getBool("enable_experimental"))
1268 // Get all data except the command number
1269 std::string datastring((char*)&data[2], datasize-2);
1270 // Throw them in an istringstream
1271 std::istringstream is(datastring, std::ios_base::binary);
1273 while(is.eof() == false)
1277 u16 id = readU16((u8*)buf);
1281 u16 message_size = readU16((u8*)buf);
1282 std::string message;
1283 message.reserve(message_size);
1284 for(u16 i=0; i<message_size; i++)
1287 message.append(buf, 1);
1289 // Pass on to the environment
1291 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1292 m_env.processActiveObjectMessage(id, message);
1299 dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command "
1300 <<command<<std::endl;
1303 // Default to queueing it (for slow commands)
1306 JMutexAutoLock lock(m_incoming_queue_mutex);
1308 IncomingPacket packet(data, datasize);
1309 m_incoming_queue.push_back(packet);
1316 Returns true if there was something in queue
1318 bool Client::AsyncProcessPacket()
1320 DSTACK(__FUNCTION_NAME);
1322 try //for catching con::PeerNotFoundException
1327 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1328 // All data is coming from the server
1329 peer = m_con.GetPeer(PEER_ID_SERVER);
1332 u8 ser_version = m_server_ser_ver;
1334 IncomingPacket packet = getPacket();
1335 u8 *data = packet.m_data;
1336 u32 datasize = packet.m_datalen;
1338 // An empty packet means queue is empty
1346 ToClientCommand command = (ToClientCommand)readU16(&data[0]);
1348 if(command == TOCLIENT_BLOCKDATA)
1350 // Ignore too small packet
1355 p.X = readS16(&data[2]);
1356 p.Y = readS16(&data[4]);
1357 p.Z = readS16(&data[6]);
1359 /*dout_client<<DTIME<<"Client: Thread: BLOCKDATA for ("
1360 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1361 /*dstream<<DTIME<<"Client: Thread: BLOCKDATA for ("
1362 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1364 std::string datastring((char*)&data[8], datasize-8);
1365 std::istringstream istr(datastring, std::ios_base::binary);
1371 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1373 v2s16 p2d(p.X, p.Z);
1374 sector = m_env.getMap().emergeSector(p2d);
1376 v2s16 sp = sector->getPos();
1379 dstream<<"ERROR: Got sector with getPos()="
1380 <<"("<<sp.X<<","<<sp.Y<<"), tried to get"
1381 <<"("<<p2d.X<<","<<p2d.Y<<")"<<std::endl;
1385 //assert(sector->getPos() == p2d);
1387 //TimeTaker timer("MapBlock deSerialize");
1391 block = sector->getBlockNoCreate(p.Y);
1393 Update an existing block
1395 //dstream<<"Updating"<<std::endl;
1396 block->deSerialize(istr, ser_version);
1397 //block->setChangedFlag();
1399 catch(InvalidPositionException &e)
1404 //dstream<<"Creating new"<<std::endl;
1405 block = new MapBlock(&m_env.getMap(), p);
1406 block->deSerialize(istr, ser_version);
1407 sector->insertBlock(block);
1408 //block->setChangedFlag();
1412 mod.type = NODEMOD_CHANGECONTENT;
1413 mod.param = CONTENT_MESE;
1414 block->setTempMod(v3s16(8,10,8), mod);
1415 block->setTempMod(v3s16(8,9,8), mod);
1416 block->setTempMod(v3s16(8,8,8), mod);
1417 block->setTempMod(v3s16(8,7,8), mod);
1418 block->setTempMod(v3s16(8,6,8), mod);*/
1422 Well, this is a dumb way to do it, they should just
1423 be drawn as separate objects. But the looks of them
1424 can be tested this way.
1429 mod.type = NODEMOD_CHANGECONTENT;
1430 mod.param = CONTENT_CLOUD;
1433 for(p2.X=3; p2.X<=13; p2.X++)
1434 for(p2.Z=3; p2.Z<=13; p2.Z++)
1436 block->setTempMod(p2, mod);
1453 u32 replysize = 2+1+6;
1454 SharedBuffer<u8> reply(replysize);
1455 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
1457 writeV3S16(&reply[3], p);
1459 m_con.Send(PEER_ID_SERVER, 1, reply, true);
1462 Update Mesh of this block and blocks at x-, y- and z-.
1463 Environment should not be locked as it interlocks with the
1464 main thread, from which is will want to retrieve textures.
1467 //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
1471 //TimeTaker timer("data fill");
1473 data.fill(getDayNightRatio(), block);
1476 TimeTaker timer("make mesh");
1477 scene::SMesh *mesh_new = NULL;
1478 mesh_new = makeMapBlockMesh(&data);
1479 block->replaceMesh(mesh_new);
1484 dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command "
1485 <<command<<std::endl;
1491 catch(con::PeerNotFoundException &e)
1493 /*dout_client<<DTIME<<"Client::AsyncProcessData(): Cancelling: The server"
1494 " connection doesn't exist (a timeout or not yet connected?)"<<std::endl;*/
1499 bool Client::AsyncProcessData()
1503 bool r = AsyncProcessPacket();
1511 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1513 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1514 m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1518 IncomingPacket Client::getPacket()
1520 JMutexAutoLock lock(m_incoming_queue_mutex);
1522 core::list<IncomingPacket>::Iterator i;
1523 // Refer to first one
1524 i = m_incoming_queue.begin();
1526 // If queue is empty, return empty packet
1527 if(i == m_incoming_queue.end()){
1528 IncomingPacket packet;
1532 // Pop out first packet and return it
1533 IncomingPacket packet = *i;
1534 m_incoming_queue.erase(i);
1539 void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
1540 v3s16 nodepos_oversurface, u16 item)
1542 if(connectedAndInitialized() == false){
1543 dout_client<<DTIME<<"Client::groundAction() "
1544 "cancelled (not connected)"
1553 [3] v3s16 nodepos_undersurface
1554 [9] v3s16 nodepos_abovesurface
1559 2: stop digging (all parameters ignored)
1560 3: digging completed
1562 u8 datasize = 2 + 1 + 6 + 6 + 2;
1563 SharedBuffer<u8> data(datasize);
1564 writeU16(&data[0], TOSERVER_GROUND_ACTION);
1565 writeU8(&data[2], action);
1566 writeV3S16(&data[3], nodepos_undersurface);
1567 writeV3S16(&data[9], nodepos_oversurface);
1568 writeU16(&data[15], item);
1569 Send(0, data, true);
1572 void Client::clickObject(u8 button, v3s16 blockpos, s16 id, u16 item)
1574 if(connectedAndInitialized() == false){
1575 dout_client<<DTIME<<"Client::clickObject() "
1576 "cancelled (not connected)"
1582 [0] u16 command=TOSERVER_CLICK_OBJECT
1583 [2] u8 button (0=left, 1=right)
1588 u8 datasize = 2 + 1 + 6 + 2 + 2;
1589 SharedBuffer<u8> data(datasize);
1590 writeU16(&data[0], TOSERVER_CLICK_OBJECT);
1591 writeU8(&data[2], button);
1592 writeV3S16(&data[3], blockpos);
1593 writeS16(&data[9], id);
1594 writeU16(&data[11], item);
1595 Send(0, data, true);
1598 void Client::clickActiveObject(u8 button, u16 id, u16 item)
1600 if(connectedAndInitialized() == false){
1601 dout_client<<DTIME<<"Client::clickActiveObject() "
1602 "cancelled (not connected)"
1610 [2] u8 button (0=left, 1=right)
1614 u8 datasize = 2 + 1 + 6 + 2 + 2;
1615 SharedBuffer<u8> data(datasize);
1616 writeU16(&data[0], TOSERVER_CLICK_ACTIVEOBJECT);
1617 writeU8(&data[2], button);
1618 writeU16(&data[3], id);
1619 writeU16(&data[5], item);
1620 Send(0, data, true);
1623 void Client::sendSignText(v3s16 blockpos, s16 id, std::string text)
1632 std::ostringstream os(std::ios_base::binary);
1636 writeU16(buf, TOSERVER_SIGNTEXT);
1637 os.write((char*)buf, 2);
1640 writeV3S16(buf, blockpos);
1641 os.write((char*)buf, 6);
1645 os.write((char*)buf, 2);
1647 u16 textlen = text.size();
1648 // Write text length
1649 writeS16(buf, textlen);
1650 os.write((char*)buf, 2);
1653 os.write((char*)text.c_str(), textlen);
1656 std::string s = os.str();
1657 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1659 Send(0, data, true);
1662 void Client::sendSignNodeText(v3s16 p, std::string text)
1670 std::ostringstream os(std::ios_base::binary);
1674 writeU16(buf, TOSERVER_SIGNNODETEXT);
1675 os.write((char*)buf, 2);
1679 os.write((char*)buf, 6);
1681 u16 textlen = text.size();
1682 // Write text length
1683 writeS16(buf, textlen);
1684 os.write((char*)buf, 2);
1687 os.write((char*)text.c_str(), textlen);
1690 std::string s = os.str();
1691 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1693 Send(0, data, true);
1696 void Client::sendInventoryAction(InventoryAction *a)
1698 std::ostringstream os(std::ios_base::binary);
1702 writeU16(buf, TOSERVER_INVENTORY_ACTION);
1703 os.write((char*)buf, 2);
1708 std::string s = os.str();
1709 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1711 Send(0, data, true);
1714 void Client::sendChatMessage(const std::wstring &message)
1716 std::ostringstream os(std::ios_base::binary);
1720 writeU16(buf, TOSERVER_CHAT_MESSAGE);
1721 os.write((char*)buf, 2);
1724 writeU16(buf, message.size());
1725 os.write((char*)buf, 2);
1728 for(u32 i=0; i<message.size(); i++)
1732 os.write((char*)buf, 2);
1736 std::string s = os.str();
1737 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1739 Send(0, data, true);
1742 void Client::sendPlayerPos()
1744 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1746 Player *myplayer = m_env.getLocalPlayer();
1747 if(myplayer == NULL)
1752 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1753 our_peer_id = m_con.GetPeerID();
1756 // Set peer id if not set already
1757 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1758 myplayer->peer_id = our_peer_id;
1759 // Check that an existing peer_id is the same as the connection's
1760 assert(myplayer->peer_id == our_peer_id);
1762 v3f pf = myplayer->getPosition();
1763 v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1764 v3f sf = myplayer->getSpeed();
1765 v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1766 s32 pitch = myplayer->getPitch() * 100;
1767 s32 yaw = myplayer->getYaw() * 100;
1772 [2] v3s32 position*100
1773 [2+12] v3s32 speed*100
1774 [2+12+12] s32 pitch*100
1775 [2+12+12+4] s32 yaw*100
1778 SharedBuffer<u8> data(2+12+12+4+4);
1779 writeU16(&data[0], TOSERVER_PLAYERPOS);
1780 writeV3S32(&data[2], position);
1781 writeV3S32(&data[2+12], speed);
1782 writeS32(&data[2+12+12], pitch);
1783 writeS32(&data[2+12+12+4], yaw);
1785 // Send as unreliable
1786 Send(0, data, false);
1789 void Client::removeNode(v3s16 p)
1791 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1793 core::map<v3s16, MapBlock*> modified_blocks;
1797 //TimeTaker t("removeNodeAndUpdate", m_device);
1798 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1800 catch(InvalidPositionException &e)
1804 for(core::map<v3s16, MapBlock * >::Iterator
1805 i = modified_blocks.getIterator();
1806 i.atEnd() == false; i++)
1808 v3s16 p = i.getNode()->getKey();
1809 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1810 addUpdateMeshTaskWithEdge(p);
1814 void Client::addNode(v3s16 p, MapNode n)
1816 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1818 TimeTaker timer1("Client::addNode()");
1820 core::map<v3s16, MapBlock*> modified_blocks;
1824 TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1825 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
1827 catch(InvalidPositionException &e)
1830 //TimeTaker timer2("Client::addNode(): updateMeshes");
1832 for(core::map<v3s16, MapBlock * >::Iterator
1833 i = modified_blocks.getIterator();
1834 i.atEnd() == false; i++)
1836 v3s16 p = i.getNode()->getKey();
1837 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1838 addUpdateMeshTaskWithEdge(p);
1842 void Client::updateCamera(v3f pos, v3f dir)
1844 m_env.getClientMap().updateCamera(pos, dir);
1845 camera_position = pos;
1846 camera_direction = dir;
1849 MapNode Client::getNode(v3s16 p)
1851 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1852 return m_env.getMap().getNode(p);
1855 NodeMetadata* Client::getNodeMetadata(v3s16 p)
1857 return m_env.getMap().getNodeMetadata(p);
1860 v3f Client::getPlayerPosition()
1862 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1863 LocalPlayer *player = m_env.getLocalPlayer();
1864 assert(player != NULL);
1865 return player->getPosition();
1868 void Client::setPlayerControl(PlayerControl &control)
1870 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1871 LocalPlayer *player = m_env.getLocalPlayer();
1872 assert(player != NULL);
1873 player->control = control;
1876 // Returns true if the inventory of the local player has been
1877 // updated from the server. If it is true, it is set to false.
1878 bool Client::getLocalInventoryUpdated()
1880 // m_inventory_updated is behind envlock
1881 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1882 bool updated = m_inventory_updated;
1883 m_inventory_updated = false;
1887 // Copies the inventory of the local player to parameter
1888 void Client::getLocalInventory(Inventory &dst)
1890 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1891 Player *player = m_env.getLocalPlayer();
1892 assert(player != NULL);
1893 dst = player->inventory;
1896 InventoryContext *Client::getInventoryContext()
1898 return &m_inventory_context;
1901 Inventory* Client::getInventory(InventoryContext *c, std::string id)
1903 if(id == "current_player")
1905 assert(c->current_player);
1906 return &(c->current_player->inventory);
1910 std::string id0 = fn.next(":");
1912 if(id0 == "nodemeta")
1915 p.X = stoi(fn.next(","));
1916 p.Y = stoi(fn.next(","));
1917 p.Z = stoi(fn.next(","));
1918 NodeMetadata* meta = getNodeMetadata(p);
1920 return meta->getInventory();
1921 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
1922 <<"no metadata found"<<std::endl;
1926 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
1929 void Client::inventoryAction(InventoryAction *a)
1931 sendInventoryAction(a);
1934 MapBlockObject * Client::getSelectedObject(
1936 v3f from_pos_f_on_map,
1937 core::line3d<f32> shootline_on_map
1940 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1942 core::array<DistanceSortedObject> objects;
1944 for(core::map<v3s16, bool>::Iterator
1945 i = m_active_blocks.getIterator();
1946 i.atEnd() == false; i++)
1948 v3s16 p = i.getNode()->getKey();
1950 MapBlock *block = NULL;
1953 block = m_env.getMap().getBlockNoCreate(p);
1955 catch(InvalidPositionException &e)
1960 // Calculate from_pos relative to block
1961 v3s16 block_pos_i_on_map = block->getPosRelative();
1962 v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
1963 v3f from_pos_f_on_block = from_pos_f_on_map - block_pos_f_on_map;
1965 block->getObjects(from_pos_f_on_block, max_d, objects);
1966 //block->getPseudoObjects(from_pos_f_on_block, max_d, objects);
1969 //dstream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
1972 // After this, the closest object is the first in the array.
1975 for(u32 i=0; i<objects.size(); i++)
1977 MapBlockObject *obj = objects[i].obj;
1978 MapBlock *block = obj->getBlock();
1980 // Calculate shootline relative to block
1981 v3s16 block_pos_i_on_map = block->getPosRelative();
1982 v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
1983 core::line3d<f32> shootline_on_block(
1984 shootline_on_map.start - block_pos_f_on_map,
1985 shootline_on_map.end - block_pos_f_on_map
1988 if(obj->isSelected(shootline_on_block))
1990 //dstream<<"Returning selected object"<<std::endl;
1995 //dstream<<"No object selected; returning NULL."<<std::endl;
1999 ClientActiveObject * Client::getSelectedActiveObject(
2001 v3f from_pos_f_on_map,
2002 core::line3d<f32> shootline_on_map
2005 core::array<DistanceSortedActiveObject> objects;
2007 m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2009 //dstream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2012 // After this, the closest object is the first in the array.
2015 for(u32 i=0; i<objects.size(); i++)
2017 ClientActiveObject *obj = objects[i].obj;
2019 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2020 if(selection_box == NULL)
2023 v3f pos = obj->getPosition();
2025 core::aabbox3d<f32> offsetted_box(
2026 selection_box->MinEdge + pos,
2027 selection_box->MaxEdge + pos
2030 if(offsetted_box.intersectsWithLine(shootline_on_map))
2032 //dstream<<"Returning selected object"<<std::endl;
2037 //dstream<<"No object selected; returning NULL."<<std::endl;
2041 void Client::printDebugInfo(std::ostream &os)
2043 //JMutexAutoLock lock1(m_fetchblock_mutex);
2044 /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2046 os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2047 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2048 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2052 /*s32 Client::getDayNightIndex()
2054 assert(m_daynight_i >= 0 && m_daynight_i < DAYNIGHT_CACHE_COUNT);
2055 return m_daynight_i;
2058 u32 Client::getDayNightRatio()
2060 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2061 return m_env.getDayNightRatio();
2064 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
2066 /*dstream<<"Client::addUpdateMeshTask(): "
2067 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2070 MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2075 Create a task to update the mesh of the block
2078 MeshMakeData *data = new MeshMakeData;
2081 //TimeTaker timer("data fill");
2083 data->fill(getDayNightRatio(), b);
2087 //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2089 // Add task to queue
2090 m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server);
2092 /*dstream<<"Mesh update input queue size is "
2093 <<m_mesh_update_thread.m_queue_in.size()
2097 // Temporary test: make mesh directly in here
2099 //TimeTaker timer("make mesh");
2101 scene::SMesh *mesh_new = NULL;
2102 mesh_new = makeMapBlockMesh(data);
2103 b->replaceMesh(mesh_new);
2108 b->setMeshExpired(false);
2111 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
2115 dstream<<"Client::addUpdateMeshTaskWithEdge(): "
2116 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2121 v3s16 p = blockpos + v3s16(0,0,0);
2122 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2123 addUpdateMeshTask(p, ack_to_server);
2125 catch(InvalidPositionException &e){}
2128 v3s16 p = blockpos + v3s16(-1,0,0);
2129 addUpdateMeshTask(p);
2131 catch(InvalidPositionException &e){}
2133 v3s16 p = blockpos + v3s16(0,-1,0);
2134 addUpdateMeshTask(p);
2136 catch(InvalidPositionException &e){}
2138 v3s16 p = blockpos + v3s16(0,0,-1);
2139 addUpdateMeshTask(p);
2141 catch(InvalidPositionException &e){}