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,
72 MapDrawControl &control):
73 m_mesh_update_thread(),
75 new ClientMap(this, control,
76 device->getSceneManager()->getRootSceneNode(),
77 device->getSceneManager(), 666),
78 device->getSceneManager()
80 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
82 camera_position(0,0,0),
83 camera_direction(0,0,1),
84 m_server_ser_ver(SER_FMT_VER_INVALID),
85 m_inventory_updated(false),
89 m_access_denied(false)
91 m_packetcounter_timer = 0.0;
92 m_delete_unused_sectors_timer = 0.0;
93 m_connection_reinit_timer = 0.0;
94 m_avg_rtt_timer = 0.0;
95 m_playerpos_send_timer = 0.0;
96 m_ignore_damage_timer = 0.0;
101 m_mesh_update_thread.Start();
107 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
109 Player *player = new LocalPlayer();
111 player->updateName(playername);
113 m_env.addPlayer(player);
115 // Initialize player in the inventory context
116 m_inventory_context.current_player = player;
123 //JMutexAutoLock conlock(m_con_mutex); //bulk comment-out
127 m_mesh_update_thread.setRun(false);
128 while(m_mesh_update_thread.IsRunning())
132 void Client::connect(Address address)
134 DSTACK(__FUNCTION_NAME);
135 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
136 m_con.setTimeoutMs(0);
137 m_con.Connect(address);
140 bool Client::connectedAndInitialized()
142 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
144 if(m_con.Connected() == false)
147 if(m_server_ser_ver == SER_FMT_VER_INVALID)
153 void Client::step(float dtime)
155 DSTACK(__FUNCTION_NAME);
161 if(m_ignore_damage_timer > dtime)
162 m_ignore_damage_timer -= dtime;
164 m_ignore_damage_timer = 0.0;
166 //dstream<<"Client steps "<<dtime<<std::endl;
169 //TimeTaker timer("ReceiveAll()", m_device);
175 //TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device);
177 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
178 m_con.RunTimeouts(dtime);
185 float &counter = m_packetcounter_timer;
191 dout_client<<"Client packetcounter (20s):"<<std::endl;
192 m_packetcounter.print(dout_client);
193 m_packetcounter.clear();
199 Delete unused sectors
201 NOTE: This jams the game for a while because deleting sectors
205 float &counter = m_delete_unused_sectors_timer;
213 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
215 core::list<v3s16> deleted_blocks;
217 float delete_unused_sectors_timeout =
218 g_settings.getFloat("client_delete_unused_sectors_timeout");
220 // Delete sector blocks
221 /*u32 num = m_env.getMap().deleteUnusedSectors
222 (delete_unused_sectors_timeout,
223 true, &deleted_blocks);*/
225 // Delete whole sectors
226 u32 num = m_env.getMap().deleteUnusedSectors
227 (delete_unused_sectors_timeout,
228 false, &deleted_blocks);
232 /*dstream<<DTIME<<"Client: Deleted blocks of "<<num
233 <<" unused sectors"<<std::endl;*/
234 dstream<<DTIME<<"Client: Deleted "<<num
235 <<" unused sectors"<<std::endl;
241 // Env is locked so con can be locked.
242 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
244 core::list<v3s16>::Iterator i = deleted_blocks.begin();
245 core::list<v3s16> sendlist;
248 if(sendlist.size() == 255 || i == deleted_blocks.end())
250 if(sendlist.size() == 0)
259 u32 replysize = 2+1+6*sendlist.size();
260 SharedBuffer<u8> reply(replysize);
261 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
262 reply[2] = sendlist.size();
264 for(core::list<v3s16>::Iterator
265 j = sendlist.begin();
266 j != sendlist.end(); j++)
268 writeV3S16(&reply[2+1+6*k], *j);
271 m_con.Send(PEER_ID_SERVER, 1, reply, true);
273 if(i == deleted_blocks.end())
279 sendlist.push_back(*i);
286 bool connected = connectedAndInitialized();
288 if(connected == false)
290 float &counter = m_connection_reinit_timer;
296 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
298 Player *myplayer = m_env.getLocalPlayer();
299 assert(myplayer != NULL);
301 // Send TOSERVER_INIT
302 // [0] u16 TOSERVER_INIT
303 // [2] u8 SER_FMT_VER_HIGHEST
304 // [3] u8[20] player_name
305 // [23] u8[28] password
306 SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE);
307 writeU16(&data[0], TOSERVER_INIT);
308 writeU8(&data[2], SER_FMT_VER_HIGHEST);
309 memset((char*)&data[3], 0, PLAYERNAME_SIZE);
310 snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
311 snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
313 // Send as unreliable
314 Send(0, data, false);
317 // Not connected, return
322 Do stuff if connected
330 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
332 // Control local player (0ms)
333 LocalPlayer *player = m_env.getLocalPlayer();
334 assert(player != NULL);
335 player->applyControl(dtime);
337 //TimeTaker envtimer("env step", m_device);
341 // Step active blocks
342 for(core::map<v3s16, bool>::Iterator
343 i = m_active_blocks.getIterator();
344 i.atEnd() == false; i++)
346 v3s16 p = i.getNode()->getKey();
348 MapBlock *block = NULL;
351 block = m_env.getMap().getBlockNoCreate(p);
352 block->stepObjects(dtime, false, m_env.getDayNightRatio());
354 catch(InvalidPositionException &e)
364 ClientEnvEvent event = m_env.getClientEvent();
365 if(event.type == CEE_NONE)
369 else if(event.type == CEE_PLAYER_DAMAGE)
371 if(m_ignore_damage_timer <= 0)
373 u8 damage = event.player_damage.amount;
376 // Add to ClientEvent queue
378 event.type = CE_PLAYER_DAMAGE;
379 event.player_damage.amount = damage;
380 m_client_event_queue.push_back(event);
390 float &counter = m_avg_rtt_timer;
395 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
396 // connectedAndInitialized() is true, peer exists.
397 con::Peer *peer = m_con.GetPeer(PEER_ID_SERVER);
398 dstream<<DTIME<<"Client: avg_rtt="<<peer->avg_rtt<<std::endl;
403 Send player position to server
406 float &counter = m_playerpos_send_timer;
416 Replace updated meshes
419 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
421 //TimeTaker timer("** Processing mesh update result queue");
424 /*dstream<<"Mesh update result queue size is "
425 <<m_mesh_update_thread.m_queue_out.size()
428 while(m_mesh_update_thread.m_queue_out.size() > 0)
430 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
431 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
434 block->replaceMesh(r.mesh);
436 if(r.ack_block_to_server)
438 /*dstream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
439 <<","<<r.p.Z<<")"<<std::endl;*/
450 u32 replysize = 2+1+6;
451 SharedBuffer<u8> reply(replysize);
452 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
454 writeV3S16(&reply[3], r.p);
456 m_con.Send(PEER_ID_SERVER, 1, reply, true);
462 // Virtual methods from con::PeerHandler
463 void Client::peerAdded(con::Peer *peer)
465 derr_client<<"Client::peerAdded(): peer->id="
466 <<peer->id<<std::endl;
468 void Client::deletingPeer(con::Peer *peer, bool timeout)
470 derr_client<<"Client::deletingPeer(): "
471 "Server Peer is getting deleted "
472 <<"(timeout="<<timeout<<")"<<std::endl;
475 void Client::ReceiveAll()
477 DSTACK(__FUNCTION_NAME);
483 catch(con::NoIncomingDataException &e)
487 catch(con::InvalidIncomingDataException &e)
489 dout_client<<DTIME<<"Client::ReceiveAll(): "
490 "InvalidIncomingDataException: what()="
491 <<e.what()<<std::endl;
496 void Client::Receive()
498 DSTACK(__FUNCTION_NAME);
499 u32 data_maxsize = 200000;
500 Buffer<u8> data(data_maxsize);
504 //TimeTaker t1("con mutex and receive", m_device);
505 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
506 datasize = m_con.Receive(sender_peer_id, *data, data_maxsize);
508 //TimeTaker t1("ProcessData", m_device);
509 ProcessData(*data, datasize, sender_peer_id);
513 sender_peer_id given to this shall be quaranteed to be a valid peer
515 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
517 DSTACK(__FUNCTION_NAME);
519 // Ignore packets that don't even fit a command
522 m_packetcounter.add(60000);
526 ToClientCommand command = (ToClientCommand)readU16(&data[0]);
528 //dstream<<"Client: received command="<<command<<std::endl;
529 m_packetcounter.add((u16)command);
532 If this check is removed, be sure to change the queue
533 system to know the ids
535 if(sender_peer_id != PEER_ID_SERVER)
537 dout_client<<DTIME<<"Client::ProcessData(): Discarding data not "
538 "coming from server: peer_id="<<sender_peer_id
545 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
546 // All data is coming from the server
547 // PeerNotFoundException is handled by caller.
548 peer = m_con.GetPeer(PEER_ID_SERVER);
551 u8 ser_version = m_server_ser_ver;
553 //dstream<<"Client received command="<<(int)command<<std::endl;
555 if(command == TOCLIENT_INIT)
560 u8 deployed = data[2];
562 dout_client<<DTIME<<"Client: TOCLIENT_INIT received with "
563 "deployed="<<((int)deployed&0xff)<<std::endl;
565 if(deployed < SER_FMT_VER_LOWEST
566 || deployed > SER_FMT_VER_HIGHEST)
568 derr_client<<DTIME<<"Client: TOCLIENT_INIT: Server sent "
569 <<"unsupported ser_fmt_ver"<<std::endl;
573 m_server_ser_ver = deployed;
575 // Get player position
576 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
577 if(datasize >= 2+1+6)
578 playerpos_s16 = readV3S16(&data[2+1]);
579 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
582 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
584 // Set player position
585 Player *player = m_env.getLocalPlayer();
586 assert(player != NULL);
587 player->setPosition(playerpos_f);
590 if(datasize >= 2+1+6+8)
593 m_map_seed = readU64(&data[2+1+6]);
594 dstream<<"Client: received map seed: "<<m_map_seed<<std::endl;
599 SharedBuffer<u8> reply(replysize);
600 writeU16(&reply[0], TOSERVER_INIT2);
602 m_con.Send(PEER_ID_SERVER, 1, reply, true);
607 if(command == TOCLIENT_ACCESS_DENIED)
609 // The server didn't like our password. Note, this needs
610 // to be processed even if the serialisation format has
611 // not been agreed yet, the same as TOCLIENT_INIT.
612 m_access_denied = true;
616 if(ser_version == SER_FMT_VER_INVALID)
618 dout_client<<DTIME<<"WARNING: Client: Server serialization"
619 " format invalid or not initialized."
620 " Skipping incoming command="<<command<<std::endl;
624 // Just here to avoid putting the two if's together when
625 // making some copypasta
628 if(command == TOCLIENT_REMOVENODE)
633 p.X = readS16(&data[2]);
634 p.Y = readS16(&data[4]);
635 p.Z = readS16(&data[6]);
637 //TimeTaker t1("TOCLIENT_REMOVENODE");
639 // This will clear the cracking animation after digging
640 ((ClientMap&)m_env.getMap()).clearTempMod(p);
644 else if(command == TOCLIENT_ADDNODE)
646 if(datasize < 8 + MapNode::serializedLength(ser_version))
650 p.X = readS16(&data[2]);
651 p.Y = readS16(&data[4]);
652 p.Z = readS16(&data[6]);
654 //TimeTaker t1("TOCLIENT_ADDNODE");
657 n.deSerialize(&data[8], ser_version);
661 else if(command == TOCLIENT_BLOCKDATA)
663 // Ignore too small packet
668 p.X = readS16(&data[2]);
669 p.Y = readS16(&data[4]);
670 p.Z = readS16(&data[6]);
672 /*dout_client<<DTIME<<"Client: Thread: BLOCKDATA for ("
673 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
674 /*dstream<<DTIME<<"Client: Thread: BLOCKDATA for ("
675 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
677 std::string datastring((char*)&data[8], datasize-8);
678 std::istringstream istr(datastring, std::ios_base::binary);
684 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
687 sector = m_env.getMap().emergeSector(p2d);
689 v2s16 sp = sector->getPos();
692 dstream<<"ERROR: Got sector with getPos()="
693 <<"("<<sp.X<<","<<sp.Y<<"), tried to get"
694 <<"("<<p2d.X<<","<<p2d.Y<<")"<<std::endl;
698 //assert(sector->getPos() == p2d);
700 //TimeTaker timer("MapBlock deSerialize");
704 block = sector->getBlockNoCreate(p.Y);
706 Update an existing block
708 //dstream<<"Updating"<<std::endl;
709 block->deSerialize(istr, ser_version);
710 //block->setChangedFlag();
712 catch(InvalidPositionException &e)
717 //dstream<<"Creating new"<<std::endl;
718 block = new MapBlock(&m_env.getMap(), p);
719 block->deSerialize(istr, ser_version);
720 sector->insertBlock(block);
721 //block->setChangedFlag();
725 mod.type = NODEMOD_CHANGECONTENT;
726 mod.param = CONTENT_MESE;
727 block->setTempMod(v3s16(8,10,8), mod);
728 block->setTempMod(v3s16(8,9,8), mod);
729 block->setTempMod(v3s16(8,8,8), mod);
730 block->setTempMod(v3s16(8,7,8), mod);
731 block->setTempMod(v3s16(8,6,8), mod);*/
735 Well, this is a dumb way to do it, they should just
736 be drawn as separate objects. But the looks of them
737 can be tested this way.
742 mod.type = NODEMOD_CHANGECONTENT;
743 mod.param = CONTENT_CLOUD;
746 for(p2.X=3; p2.X<=13; p2.X++)
747 for(p2.Z=3; p2.Z<=13; p2.Z++)
749 block->setTempMod(p2, mod);
767 u32 replysize = 2+1+6;
768 SharedBuffer<u8> reply(replysize);
769 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
771 writeV3S16(&reply[3], p);
773 m_con.Send(PEER_ID_SERVER, 1, reply, true);
777 Update Mesh of this block and blocks at x-, y- and z-.
778 Environment should not be locked as it interlocks with the
779 main thread, from which is will want to retrieve textures.
782 //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
784 addUpdateMeshTaskWithEdge(p, true);
786 else if(command == TOCLIENT_PLAYERPOS)
788 dstream<<"WARNING: Received deprecated TOCLIENT_PLAYERPOS"
792 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
793 our_peer_id = m_con.GetPeerID();
795 // Cancel if we don't have a peer id
796 if(our_peer_id == PEER_ID_INEXISTENT){
797 dout_client<<DTIME<<"TOCLIENT_PLAYERPOS cancelled: "
804 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
806 u32 player_size = 2+12+12+4+4;
808 u32 player_count = (datasize-2) / player_size;
810 for(u32 i=0; i<player_count; i++)
812 u16 peer_id = readU16(&data[start]);
814 Player *player = m_env.getPlayer(peer_id);
816 // Skip if player doesn't exist
819 start += player_size;
823 // Skip if player is local player
824 if(player->isLocal())
826 start += player_size;
830 v3s32 ps = readV3S32(&data[start+2]);
831 v3s32 ss = readV3S32(&data[start+2+12]);
832 s32 pitch_i = readS32(&data[start+2+12+12]);
833 s32 yaw_i = readS32(&data[start+2+12+12+4]);
834 /*dstream<<"Client: got "
835 <<"pitch_i="<<pitch_i
836 <<" yaw_i="<<yaw_i<<std::endl;*/
837 f32 pitch = (f32)pitch_i / 100.0;
838 f32 yaw = (f32)yaw_i / 100.0;
839 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
840 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
841 player->setPosition(position);
842 player->setSpeed(speed);
843 player->setPitch(pitch);
846 /*dstream<<"Client: player "<<peer_id
848 <<" yaw="<<yaw<<std::endl;*/
850 start += player_size;
854 else if(command == TOCLIENT_PLAYERINFO)
858 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
859 our_peer_id = m_con.GetPeerID();
861 // Cancel if we don't have a peer id
862 if(our_peer_id == PEER_ID_INEXISTENT){
863 dout_client<<DTIME<<"TOCLIENT_PLAYERINFO cancelled: "
869 //dstream<<DTIME<<"Client: Server reports players:"<<std::endl;
872 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
874 u32 item_size = 2+PLAYERNAME_SIZE;
875 u32 player_count = (datasize-2) / item_size;
878 core::list<u16> players_alive;
879 for(u32 i=0; i<player_count; i++)
881 // Make sure the name ends in '\0'
882 data[start+2+20-1] = 0;
884 u16 peer_id = readU16(&data[start]);
886 players_alive.push_back(peer_id);
888 /*dstream<<DTIME<<"peer_id="<<peer_id
889 <<" name="<<((char*)&data[start+2])<<std::endl;*/
891 // Don't update the info of the local player
892 if(peer_id == our_peer_id)
898 Player *player = m_env.getPlayer(peer_id);
900 // Create a player if it doesn't exist
903 player = new RemotePlayer(
904 m_device->getSceneManager()->getRootSceneNode(),
907 player->peer_id = peer_id;
908 m_env.addPlayer(player);
909 dout_client<<DTIME<<"Client: Adding new player "
910 <<peer_id<<std::endl;
913 player->updateName((char*)&data[start+2]);
919 Remove those players from the environment that
920 weren't listed by the server.
922 //dstream<<DTIME<<"Removing dead players"<<std::endl;
923 core::list<Player*> players = m_env.getPlayers();
924 core::list<Player*>::Iterator ip;
925 for(ip=players.begin(); ip!=players.end(); ip++)
927 // Ingore local player
931 // Warn about a special case
932 if((*ip)->peer_id == 0)
934 dstream<<DTIME<<"WARNING: Client: Removing "
935 "dead player with id=0"<<std::endl;
938 bool is_alive = false;
939 core::list<u16>::Iterator i;
940 for(i=players_alive.begin(); i!=players_alive.end(); i++)
942 if((*ip)->peer_id == *i)
948 /*dstream<<DTIME<<"peer_id="<<((*ip)->peer_id)
949 <<" is_alive="<<is_alive<<std::endl;*/
952 dstream<<DTIME<<"Removing dead player "<<(*ip)->peer_id
954 m_env.removePlayer((*ip)->peer_id);
958 else if(command == TOCLIENT_SECTORMETA)
963 [3...] v2s16 pos + sector metadata
968 //dstream<<"Client received TOCLIENT_SECTORMETA"<<std::endl;
971 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
973 std::string datastring((char*)&data[2], datasize-2);
974 std::istringstream is(datastring, std::ios_base::binary);
978 is.read((char*)buf, 1);
979 u16 sector_count = readU8(buf);
981 //dstream<<"sector_count="<<sector_count<<std::endl;
983 for(u16 i=0; i<sector_count; i++)
986 is.read((char*)buf, 4);
987 v2s16 pos = readV2S16(buf);
988 /*dstream<<"Client: deserializing sector at "
989 <<"("<<pos.X<<","<<pos.Y<<")"<<std::endl;*/
991 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
992 ((ClientMap&)m_env.getMap()).deSerializeSector(pos, is);
996 else if(command == TOCLIENT_INVENTORY)
1001 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
1004 //TimeTaker t2("mutex locking", m_device);
1005 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1008 //TimeTaker t3("istringstream init", m_device);
1009 std::string datastring((char*)&data[2], datasize-2);
1010 std::istringstream is(datastring, std::ios_base::binary);
1013 //m_env.printPlayers(dstream);
1015 //TimeTaker t4("player get", m_device);
1016 Player *player = m_env.getLocalPlayer();
1017 assert(player != NULL);
1020 //TimeTaker t1("inventory.deSerialize()", m_device);
1021 player->inventory.deSerialize(is);
1024 m_inventory_updated = true;
1026 //dstream<<"Client got player inventory:"<<std::endl;
1027 //player->inventory.print(dstream);
1031 else if(command == TOCLIENT_OBJECTDATA)
1034 // Strip command word and create a stringstream
1035 std::string datastring((char*)&data[2], datasize-2);
1036 std::istringstream is(datastring, std::ios_base::binary);
1040 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1048 is.read((char*)buf, 2);
1049 u16 playercount = readU16(buf);
1051 for(u16 i=0; i<playercount; i++)
1053 is.read((char*)buf, 2);
1054 u16 peer_id = readU16(buf);
1055 is.read((char*)buf, 12);
1056 v3s32 p_i = readV3S32(buf);
1057 is.read((char*)buf, 12);
1058 v3s32 s_i = readV3S32(buf);
1059 is.read((char*)buf, 4);
1060 s32 pitch_i = readS32(buf);
1061 is.read((char*)buf, 4);
1062 s32 yaw_i = readS32(buf);
1064 Player *player = m_env.getPlayer(peer_id);
1066 // Skip if player doesn't exist
1072 // Skip if player is local player
1073 if(player->isLocal())
1078 f32 pitch = (f32)pitch_i / 100.0;
1079 f32 yaw = (f32)yaw_i / 100.0;
1080 v3f position((f32)p_i.X/100., (f32)p_i.Y/100., (f32)p_i.Z/100.);
1081 v3f speed((f32)s_i.X/100., (f32)s_i.Y/100., (f32)s_i.Z/100.);
1083 player->setPosition(position);
1084 player->setSpeed(speed);
1085 player->setPitch(pitch);
1086 player->setYaw(yaw);
1093 // Read active block count
1094 is.read((char*)buf, 2);
1095 u16 blockcount = readU16(buf);
1097 // Initialize delete queue with all active blocks
1098 core::map<v3s16, bool> abs_to_delete;
1099 for(core::map<v3s16, bool>::Iterator
1100 i = m_active_blocks.getIterator();
1101 i.atEnd() == false; i++)
1103 v3s16 p = i.getNode()->getKey();
1104 /*dstream<<"adding "
1105 <<"("<<p.x<<","<<p.y<<","<<p.z<<") "
1106 <<" to abs_to_delete"
1108 abs_to_delete.insert(p, true);
1111 /*dstream<<"Initial delete queue size: "<<abs_to_delete.size()
1114 for(u16 i=0; i<blockcount; i++)
1117 is.read((char*)buf, 6);
1118 v3s16 p = readV3S16(buf);
1119 // Get block from somewhere
1120 MapBlock *block = NULL;
1122 block = m_env.getMap().getBlockNoCreate(p);
1124 catch(InvalidPositionException &e)
1126 //TODO: Create a dummy block?
1130 dstream<<"WARNING: "
1131 <<"Could not get block at blockpos "
1132 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
1133 <<"in TOCLIENT_OBJECTDATA. Ignoring "
1134 <<"following block object data."
1139 /*dstream<<"Client updating objects for block "
1140 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1143 // Insert to active block list
1144 m_active_blocks.insert(p, true);
1146 // Remove from deletion queue
1147 if(abs_to_delete.find(p) != NULL)
1148 abs_to_delete.remove(p);
1151 Update objects of block
1153 NOTE: Be sure this is done in the main thread.
1155 block->updateObjects(is, m_server_ser_ver,
1156 m_device->getSceneManager(), m_env.getDayNightRatio());
1159 /*dstream<<"Final delete queue size: "<<abs_to_delete.size()
1162 // Delete objects of blocks in delete queue
1163 for(core::map<v3s16, bool>::Iterator
1164 i = abs_to_delete.getIterator();
1165 i.atEnd() == false; i++)
1167 v3s16 p = i.getNode()->getKey();
1170 MapBlock *block = m_env.getMap().getBlockNoCreate(p);
1173 block->clearObjects();
1174 // Remove from active blocks list
1175 m_active_blocks.remove(p);
1177 catch(InvalidPositionException &e)
1179 dstream<<"WARNAING: Client: "
1180 <<"Couldn't clear objects of active->inactive"
1182 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1183 <<" because block was not found"
1191 else if(command == TOCLIENT_TIME_OF_DAY)
1196 u16 time_of_day = readU16(&data[2]);
1197 time_of_day = time_of_day % 24000;
1198 //dstream<<"Client: time_of_day="<<time_of_day<<std::endl;
1206 m_env.setTimeOfDay(time_of_day);
1208 u32 dr = m_env.getDayNightRatio();
1210 dstream<<"Client: time_of_day="<<time_of_day
1216 else if(command == TOCLIENT_CHAT_MESSAGE)
1224 std::string datastring((char*)&data[2], datasize-2);
1225 std::istringstream is(datastring, std::ios_base::binary);
1228 is.read((char*)buf, 2);
1229 u16 len = readU16(buf);
1231 std::wstring message;
1232 for(u16 i=0; i<len; i++)
1234 is.read((char*)buf, 2);
1235 message += (wchar_t)readU16(buf);
1238 /*dstream<<"Client received chat message: "
1239 <<wide_to_narrow(message)<<std::endl;*/
1241 m_chat_queue.push_back(message);
1243 else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1245 //if(g_settings.getBool("enable_experimental"))
1249 u16 count of removed objects
1250 for all removed objects {
1253 u16 count of added objects
1254 for all added objects {
1257 u16 initialization data length
1258 string initialization data
1263 // Get all data except the command number
1264 std::string datastring((char*)&data[2], datasize-2);
1265 // Throw them in an istringstream
1266 std::istringstream is(datastring, std::ios_base::binary);
1270 // Read removed objects
1272 u16 removed_count = readU16((u8*)buf);
1273 for(u16 i=0; i<removed_count; i++)
1276 u16 id = readU16((u8*)buf);
1279 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1280 m_env.removeActiveObject(id);
1284 // Read added objects
1286 u16 added_count = readU16((u8*)buf);
1287 for(u16 i=0; i<added_count; i++)
1290 u16 id = readU16((u8*)buf);
1292 u8 type = readU8((u8*)buf);
1293 std::string data = deSerializeLongString(is);
1296 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1297 m_env.addActiveObject(id, type, data);
1302 else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1304 //if(g_settings.getBool("enable_experimental"))
1316 // Get all data except the command number
1317 std::string datastring((char*)&data[2], datasize-2);
1318 // Throw them in an istringstream
1319 std::istringstream is(datastring, std::ios_base::binary);
1321 while(is.eof() == false)
1325 u16 id = readU16((u8*)buf);
1329 u16 message_size = readU16((u8*)buf);
1330 std::string message;
1331 message.reserve(message_size);
1332 for(u16 i=0; i<message_size; i++)
1335 message.append(buf, 1);
1337 // Pass on to the environment
1339 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1340 m_env.processActiveObjectMessage(id, message);
1345 else if(command == TOCLIENT_HP)
1347 std::string datastring((char*)&data[2], datasize-2);
1348 std::istringstream is(datastring, std::ios_base::binary);
1349 Player *player = m_env.getLocalPlayer();
1350 assert(player != NULL);
1354 else if(command == TOCLIENT_MOVE_PLAYER)
1356 std::string datastring((char*)&data[2], datasize-2);
1357 std::istringstream is(datastring, std::ios_base::binary);
1358 Player *player = m_env.getLocalPlayer();
1359 assert(player != NULL);
1360 v3f pos = readV3F1000(is);
1361 f32 pitch = readF1000(is);
1362 f32 yaw = readF1000(is);
1363 player->setPosition(pos);
1364 /*player->setPitch(pitch);
1365 player->setYaw(yaw);*/
1367 dstream<<"Client got TOCLIENT_MOVE_PLAYER"
1368 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1374 Add to ClientEvent queue.
1375 This has to be sent to the main program because otherwise
1376 it would just force the pitch and yaw values to whatever
1377 the camera points to.
1380 event.type = CE_PLAYER_FORCE_MOVE;
1381 event.player_force_move.pitch = pitch;
1382 event.player_force_move.yaw = yaw;
1383 m_client_event_queue.push_back(event);
1385 // Ignore damage for a few seconds, so that the player doesn't
1386 // get damage from falling on ground
1387 m_ignore_damage_timer = 3.0;
1391 dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command "
1392 <<command<<std::endl;
1396 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1398 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1399 m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1402 void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
1403 v3s16 nodepos_oversurface, u16 item)
1405 if(connectedAndInitialized() == false){
1406 dout_client<<DTIME<<"Client::groundAction() "
1407 "cancelled (not connected)"
1416 [3] v3s16 nodepos_undersurface
1417 [9] v3s16 nodepos_abovesurface
1422 2: stop digging (all parameters ignored)
1423 3: digging completed
1425 u8 datasize = 2 + 1 + 6 + 6 + 2;
1426 SharedBuffer<u8> data(datasize);
1427 writeU16(&data[0], TOSERVER_GROUND_ACTION);
1428 writeU8(&data[2], action);
1429 writeV3S16(&data[3], nodepos_undersurface);
1430 writeV3S16(&data[9], nodepos_oversurface);
1431 writeU16(&data[15], item);
1432 Send(0, data, true);
1435 void Client::clickObject(u8 button, v3s16 blockpos, s16 id, u16 item)
1437 if(connectedAndInitialized() == false){
1438 dout_client<<DTIME<<"Client::clickObject() "
1439 "cancelled (not connected)"
1445 [0] u16 command=TOSERVER_CLICK_OBJECT
1446 [2] u8 button (0=left, 1=right)
1451 u8 datasize = 2 + 1 + 6 + 2 + 2;
1452 SharedBuffer<u8> data(datasize);
1453 writeU16(&data[0], TOSERVER_CLICK_OBJECT);
1454 writeU8(&data[2], button);
1455 writeV3S16(&data[3], blockpos);
1456 writeS16(&data[9], id);
1457 writeU16(&data[11], item);
1458 Send(0, data, true);
1461 void Client::clickActiveObject(u8 button, u16 id, u16 item)
1463 if(connectedAndInitialized() == false){
1464 dout_client<<DTIME<<"Client::clickActiveObject() "
1465 "cancelled (not connected)"
1473 [2] u8 button (0=left, 1=right)
1477 u8 datasize = 2 + 1 + 6 + 2 + 2;
1478 SharedBuffer<u8> data(datasize);
1479 writeU16(&data[0], TOSERVER_CLICK_ACTIVEOBJECT);
1480 writeU8(&data[2], button);
1481 writeU16(&data[3], id);
1482 writeU16(&data[5], item);
1483 Send(0, data, true);
1486 void Client::sendSignText(v3s16 blockpos, s16 id, std::string text)
1495 std::ostringstream os(std::ios_base::binary);
1499 writeU16(buf, TOSERVER_SIGNTEXT);
1500 os.write((char*)buf, 2);
1503 writeV3S16(buf, blockpos);
1504 os.write((char*)buf, 6);
1508 os.write((char*)buf, 2);
1510 u16 textlen = text.size();
1511 // Write text length
1512 writeS16(buf, textlen);
1513 os.write((char*)buf, 2);
1516 os.write((char*)text.c_str(), textlen);
1519 std::string s = os.str();
1520 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1522 Send(0, data, true);
1525 void Client::sendSignNodeText(v3s16 p, std::string text)
1533 std::ostringstream os(std::ios_base::binary);
1537 writeU16(buf, TOSERVER_SIGNNODETEXT);
1538 os.write((char*)buf, 2);
1542 os.write((char*)buf, 6);
1544 u16 textlen = text.size();
1545 // Write text length
1546 writeS16(buf, textlen);
1547 os.write((char*)buf, 2);
1550 os.write((char*)text.c_str(), textlen);
1553 std::string s = os.str();
1554 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1556 Send(0, data, true);
1559 void Client::sendInventoryAction(InventoryAction *a)
1561 std::ostringstream os(std::ios_base::binary);
1565 writeU16(buf, TOSERVER_INVENTORY_ACTION);
1566 os.write((char*)buf, 2);
1571 std::string s = os.str();
1572 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1574 Send(0, data, true);
1577 void Client::sendChatMessage(const std::wstring &message)
1579 std::ostringstream os(std::ios_base::binary);
1583 writeU16(buf, TOSERVER_CHAT_MESSAGE);
1584 os.write((char*)buf, 2);
1587 writeU16(buf, message.size());
1588 os.write((char*)buf, 2);
1591 for(u32 i=0; i<message.size(); i++)
1595 os.write((char*)buf, 2);
1599 std::string s = os.str();
1600 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1602 Send(0, data, true);
1605 void Client::sendChangePassword(const std::wstring oldpassword,
1606 const std::wstring newpassword)
1608 Player *player = m_env.getLocalPlayer();
1612 std::string playername = player->getName();
1613 std::string oldpwd = translatePassword(playername, oldpassword);
1614 std::string newpwd = translatePassword(playername, newpassword);
1616 std::ostringstream os(std::ios_base::binary);
1617 u8 buf[2+PASSWORD_SIZE*2];
1619 [0] u16 TOSERVER_PASSWORD
1620 [2] u8[28] old password
1621 [30] u8[28] new password
1624 writeU16(buf, TOSERVER_PASSWORD);
1625 for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1627 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1628 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1630 buf[2+PASSWORD_SIZE-1] = 0;
1631 buf[30+PASSWORD_SIZE-1] = 0;
1632 os.write((char*)buf, 2+PASSWORD_SIZE*2);
1635 std::string s = os.str();
1636 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1638 Send(0, data, true);
1642 void Client::sendDamage(u8 damage)
1644 DSTACK(__FUNCTION_NAME);
1645 std::ostringstream os(std::ios_base::binary);
1647 writeU16(os, TOSERVER_DAMAGE);
1648 writeU8(os, damage);
1651 std::string s = os.str();
1652 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1654 Send(0, data, true);
1657 void Client::sendPlayerPos()
1659 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1661 Player *myplayer = m_env.getLocalPlayer();
1662 if(myplayer == NULL)
1667 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1668 our_peer_id = m_con.GetPeerID();
1671 // Set peer id if not set already
1672 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1673 myplayer->peer_id = our_peer_id;
1674 // Check that an existing peer_id is the same as the connection's
1675 assert(myplayer->peer_id == our_peer_id);
1677 v3f pf = myplayer->getPosition();
1678 v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1679 v3f sf = myplayer->getSpeed();
1680 v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1681 s32 pitch = myplayer->getPitch() * 100;
1682 s32 yaw = myplayer->getYaw() * 100;
1687 [2] v3s32 position*100
1688 [2+12] v3s32 speed*100
1689 [2+12+12] s32 pitch*100
1690 [2+12+12+4] s32 yaw*100
1693 SharedBuffer<u8> data(2+12+12+4+4);
1694 writeU16(&data[0], TOSERVER_PLAYERPOS);
1695 writeV3S32(&data[2], position);
1696 writeV3S32(&data[2+12], speed);
1697 writeS32(&data[2+12+12], pitch);
1698 writeS32(&data[2+12+12+4], yaw);
1700 // Send as unreliable
1701 Send(0, data, false);
1704 void Client::removeNode(v3s16 p)
1706 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1708 core::map<v3s16, MapBlock*> modified_blocks;
1712 //TimeTaker t("removeNodeAndUpdate", m_device);
1713 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1715 catch(InvalidPositionException &e)
1719 for(core::map<v3s16, MapBlock * >::Iterator
1720 i = modified_blocks.getIterator();
1721 i.atEnd() == false; i++)
1723 v3s16 p = i.getNode()->getKey();
1724 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1725 addUpdateMeshTaskWithEdge(p);
1729 void Client::addNode(v3s16 p, MapNode n)
1731 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1733 TimeTaker timer1("Client::addNode()");
1735 core::map<v3s16, MapBlock*> modified_blocks;
1739 TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1740 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
1742 catch(InvalidPositionException &e)
1745 //TimeTaker timer2("Client::addNode(): updateMeshes");
1747 for(core::map<v3s16, MapBlock * >::Iterator
1748 i = modified_blocks.getIterator();
1749 i.atEnd() == false; i++)
1751 v3s16 p = i.getNode()->getKey();
1752 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1753 addUpdateMeshTaskWithEdge(p);
1757 void Client::updateCamera(v3f pos, v3f dir)
1759 m_env.getClientMap().updateCamera(pos, dir);
1760 camera_position = pos;
1761 camera_direction = dir;
1764 MapNode Client::getNode(v3s16 p)
1766 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1767 return m_env.getMap().getNode(p);
1770 NodeMetadata* Client::getNodeMetadata(v3s16 p)
1772 return m_env.getMap().getNodeMetadata(p);
1775 v3f Client::getPlayerPosition()
1777 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1778 LocalPlayer *player = m_env.getLocalPlayer();
1779 assert(player != NULL);
1780 return player->getPosition();
1783 void Client::setPlayerControl(PlayerControl &control)
1785 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1786 LocalPlayer *player = m_env.getLocalPlayer();
1787 assert(player != NULL);
1788 player->control = control;
1791 // Returns true if the inventory of the local player has been
1792 // updated from the server. If it is true, it is set to false.
1793 bool Client::getLocalInventoryUpdated()
1795 // m_inventory_updated is behind envlock
1796 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1797 bool updated = m_inventory_updated;
1798 m_inventory_updated = false;
1802 // Copies the inventory of the local player to parameter
1803 void Client::getLocalInventory(Inventory &dst)
1805 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1806 Player *player = m_env.getLocalPlayer();
1807 assert(player != NULL);
1808 dst = player->inventory;
1811 InventoryContext *Client::getInventoryContext()
1813 return &m_inventory_context;
1816 Inventory* Client::getInventory(InventoryContext *c, std::string id)
1818 if(id == "current_player")
1820 assert(c->current_player);
1821 return &(c->current_player->inventory);
1825 std::string id0 = fn.next(":");
1827 if(id0 == "nodemeta")
1830 p.X = stoi(fn.next(","));
1831 p.Y = stoi(fn.next(","));
1832 p.Z = stoi(fn.next(","));
1833 NodeMetadata* meta = getNodeMetadata(p);
1835 return meta->getInventory();
1836 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
1837 <<"no metadata found"<<std::endl;
1841 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
1844 void Client::inventoryAction(InventoryAction *a)
1846 sendInventoryAction(a);
1849 MapBlockObject * Client::getSelectedObject(
1851 v3f from_pos_f_on_map,
1852 core::line3d<f32> shootline_on_map
1855 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1857 core::array<DistanceSortedObject> objects;
1859 for(core::map<v3s16, bool>::Iterator
1860 i = m_active_blocks.getIterator();
1861 i.atEnd() == false; i++)
1863 v3s16 p = i.getNode()->getKey();
1865 MapBlock *block = NULL;
1868 block = m_env.getMap().getBlockNoCreate(p);
1870 catch(InvalidPositionException &e)
1875 // Calculate from_pos relative to block
1876 v3s16 block_pos_i_on_map = block->getPosRelative();
1877 v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
1878 v3f from_pos_f_on_block = from_pos_f_on_map - block_pos_f_on_map;
1880 block->getObjects(from_pos_f_on_block, max_d, objects);
1881 //block->getPseudoObjects(from_pos_f_on_block, max_d, objects);
1884 //dstream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
1887 // After this, the closest object is the first in the array.
1890 for(u32 i=0; i<objects.size(); i++)
1892 MapBlockObject *obj = objects[i].obj;
1893 MapBlock *block = obj->getBlock();
1895 // Calculate shootline relative to block
1896 v3s16 block_pos_i_on_map = block->getPosRelative();
1897 v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
1898 core::line3d<f32> shootline_on_block(
1899 shootline_on_map.start - block_pos_f_on_map,
1900 shootline_on_map.end - block_pos_f_on_map
1903 if(obj->isSelected(shootline_on_block))
1905 //dstream<<"Returning selected object"<<std::endl;
1910 //dstream<<"No object selected; returning NULL."<<std::endl;
1914 ClientActiveObject * Client::getSelectedActiveObject(
1916 v3f from_pos_f_on_map,
1917 core::line3d<f32> shootline_on_map
1920 core::array<DistanceSortedActiveObject> objects;
1922 m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
1924 //dstream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
1927 // After this, the closest object is the first in the array.
1930 for(u32 i=0; i<objects.size(); i++)
1932 ClientActiveObject *obj = objects[i].obj;
1934 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
1935 if(selection_box == NULL)
1938 v3f pos = obj->getPosition();
1940 core::aabbox3d<f32> offsetted_box(
1941 selection_box->MinEdge + pos,
1942 selection_box->MaxEdge + pos
1945 if(offsetted_box.intersectsWithLine(shootline_on_map))
1947 //dstream<<"Returning selected object"<<std::endl;
1952 //dstream<<"No object selected; returning NULL."<<std::endl;
1956 void Client::printDebugInfo(std::ostream &os)
1958 //JMutexAutoLock lock1(m_fetchblock_mutex);
1959 /*JMutexAutoLock lock2(m_incoming_queue_mutex);
1961 os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
1962 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
1963 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
1967 /*s32 Client::getDayNightIndex()
1969 assert(m_daynight_i >= 0 && m_daynight_i < DAYNIGHT_CACHE_COUNT);
1970 return m_daynight_i;
1973 u32 Client::getDayNightRatio()
1975 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1976 return m_env.getDayNightRatio();
1981 Player *player = m_env.getLocalPlayer();
1982 assert(player != NULL);
1986 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
1988 /*dstream<<"Client::addUpdateMeshTask(): "
1989 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1992 MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
1997 Create a task to update the mesh of the block
2000 MeshMakeData *data = new MeshMakeData;
2003 //TimeTaker timer("data fill");
2005 data->fill(getDayNightRatio(), b);
2009 //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2011 // Add task to queue
2012 m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server);
2014 /*dstream<<"Mesh update input queue size is "
2015 <<m_mesh_update_thread.m_queue_in.size()
2019 // Temporary test: make mesh directly in here
2021 //TimeTaker timer("make mesh");
2023 scene::SMesh *mesh_new = NULL;
2024 mesh_new = makeMapBlockMesh(data);
2025 b->replaceMesh(mesh_new);
2030 b->setMeshExpired(false);
2033 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
2037 dstream<<"Client::addUpdateMeshTaskWithEdge(): "
2038 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2043 v3s16 p = blockpos + v3s16(0,0,0);
2044 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2045 addUpdateMeshTask(p, ack_to_server);
2047 catch(InvalidPositionException &e){}
2050 v3s16 p = blockpos + v3s16(-1,0,0);
2051 addUpdateMeshTask(p);
2053 catch(InvalidPositionException &e){}
2055 v3s16 p = blockpos + v3s16(0,-1,0);
2056 addUpdateMeshTask(p);
2058 catch(InvalidPositionException &e){}
2060 v3s16 p = blockpos + v3s16(0,0,-1);
2061 addUpdateMeshTask(p);
2063 catch(InvalidPositionException &e){}
2066 ClientEvent Client::getClientEvent()
2068 if(m_client_event_queue.size() == 0)
2071 event.type = CE_NONE;
2074 return m_client_event_queue.pop_front();