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);
310 memset((char*)&data[3], 0, PLAYERNAME_SIZE);
311 snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
313 /*dstream<<"Client: password hash is \""<<m_password<<"\""
316 memset((char*)&data[23], 0, PASSWORD_SIZE);
317 snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
319 // Send as unreliable
320 Send(0, data, false);
323 // Not connected, return
328 Do stuff if connected
336 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
338 // Control local player (0ms)
339 LocalPlayer *player = m_env.getLocalPlayer();
340 assert(player != NULL);
341 player->applyControl(dtime);
343 //TimeTaker envtimer("env step", m_device);
347 // Step active blocks
348 for(core::map<v3s16, bool>::Iterator
349 i = m_active_blocks.getIterator();
350 i.atEnd() == false; i++)
352 v3s16 p = i.getNode()->getKey();
354 MapBlock *block = NULL;
357 block = m_env.getMap().getBlockNoCreate(p);
358 block->stepObjects(dtime, false, m_env.getDayNightRatio());
360 catch(InvalidPositionException &e)
370 ClientEnvEvent event = m_env.getClientEvent();
371 if(event.type == CEE_NONE)
375 else if(event.type == CEE_PLAYER_DAMAGE)
377 if(m_ignore_damage_timer <= 0)
379 u8 damage = event.player_damage.amount;
382 // Add to ClientEvent queue
384 event.type = CE_PLAYER_DAMAGE;
385 event.player_damage.amount = damage;
386 m_client_event_queue.push_back(event);
396 float &counter = m_avg_rtt_timer;
401 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
402 // connectedAndInitialized() is true, peer exists.
403 con::Peer *peer = m_con.GetPeer(PEER_ID_SERVER);
404 dstream<<DTIME<<"Client: avg_rtt="<<peer->avg_rtt<<std::endl;
409 Send player position to server
412 float &counter = m_playerpos_send_timer;
422 Replace updated meshes
425 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
427 //TimeTaker timer("** Processing mesh update result queue");
430 /*dstream<<"Mesh update result queue size is "
431 <<m_mesh_update_thread.m_queue_out.size()
434 while(m_mesh_update_thread.m_queue_out.size() > 0)
436 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
437 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
440 block->replaceMesh(r.mesh);
442 if(r.ack_block_to_server)
444 /*dstream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
445 <<","<<r.p.Z<<")"<<std::endl;*/
456 u32 replysize = 2+1+6;
457 SharedBuffer<u8> reply(replysize);
458 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
460 writeV3S16(&reply[3], r.p);
462 m_con.Send(PEER_ID_SERVER, 1, reply, true);
468 // Virtual methods from con::PeerHandler
469 void Client::peerAdded(con::Peer *peer)
471 derr_client<<"Client::peerAdded(): peer->id="
472 <<peer->id<<std::endl;
474 void Client::deletingPeer(con::Peer *peer, bool timeout)
476 derr_client<<"Client::deletingPeer(): "
477 "Server Peer is getting deleted "
478 <<"(timeout="<<timeout<<")"<<std::endl;
481 void Client::ReceiveAll()
483 DSTACK(__FUNCTION_NAME);
489 catch(con::NoIncomingDataException &e)
493 catch(con::InvalidIncomingDataException &e)
495 dout_client<<DTIME<<"Client::ReceiveAll(): "
496 "InvalidIncomingDataException: what()="
497 <<e.what()<<std::endl;
502 void Client::Receive()
504 DSTACK(__FUNCTION_NAME);
505 u32 data_maxsize = 200000;
506 Buffer<u8> data(data_maxsize);
510 //TimeTaker t1("con mutex and receive", m_device);
511 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
512 datasize = m_con.Receive(sender_peer_id, *data, data_maxsize);
514 //TimeTaker t1("ProcessData", m_device);
515 ProcessData(*data, datasize, sender_peer_id);
519 sender_peer_id given to this shall be quaranteed to be a valid peer
521 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
523 DSTACK(__FUNCTION_NAME);
525 // Ignore packets that don't even fit a command
528 m_packetcounter.add(60000);
532 ToClientCommand command = (ToClientCommand)readU16(&data[0]);
534 //dstream<<"Client: received command="<<command<<std::endl;
535 m_packetcounter.add((u16)command);
538 If this check is removed, be sure to change the queue
539 system to know the ids
541 if(sender_peer_id != PEER_ID_SERVER)
543 dout_client<<DTIME<<"Client::ProcessData(): Discarding data not "
544 "coming from server: peer_id="<<sender_peer_id
551 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
552 // All data is coming from the server
553 // PeerNotFoundException is handled by caller.
554 peer = m_con.GetPeer(PEER_ID_SERVER);
557 u8 ser_version = m_server_ser_ver;
559 //dstream<<"Client received command="<<(int)command<<std::endl;
561 if(command == TOCLIENT_INIT)
566 u8 deployed = data[2];
568 dout_client<<DTIME<<"Client: TOCLIENT_INIT received with "
569 "deployed="<<((int)deployed&0xff)<<std::endl;
571 if(deployed < SER_FMT_VER_LOWEST
572 || deployed > SER_FMT_VER_HIGHEST)
574 derr_client<<DTIME<<"Client: TOCLIENT_INIT: Server sent "
575 <<"unsupported ser_fmt_ver"<<std::endl;
579 m_server_ser_ver = deployed;
581 // Get player position
582 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
583 if(datasize >= 2+1+6)
584 playerpos_s16 = readV3S16(&data[2+1]);
585 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
588 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
590 // Set player position
591 Player *player = m_env.getLocalPlayer();
592 assert(player != NULL);
593 player->setPosition(playerpos_f);
596 if(datasize >= 2+1+6+8)
599 m_map_seed = readU64(&data[2+1+6]);
600 dstream<<"Client: received map seed: "<<m_map_seed<<std::endl;
605 SharedBuffer<u8> reply(replysize);
606 writeU16(&reply[0], TOSERVER_INIT2);
608 m_con.Send(PEER_ID_SERVER, 1, reply, true);
613 if(command == TOCLIENT_ACCESS_DENIED)
615 // The server didn't like our password. Note, this needs
616 // to be processed even if the serialisation format has
617 // not been agreed yet, the same as TOCLIENT_INIT.
618 m_access_denied = true;
619 m_access_denied_reason = L"Unknown";
622 std::string datastring((char*)&data[2], datasize-2);
623 std::istringstream is(datastring, std::ios_base::binary);
624 m_access_denied_reason = deSerializeWideString(is);
629 if(ser_version == SER_FMT_VER_INVALID)
631 dout_client<<DTIME<<"WARNING: Client: Server serialization"
632 " format invalid or not initialized."
633 " Skipping incoming command="<<command<<std::endl;
637 // Just here to avoid putting the two if's together when
638 // making some copypasta
641 if(command == TOCLIENT_REMOVENODE)
646 p.X = readS16(&data[2]);
647 p.Y = readS16(&data[4]);
648 p.Z = readS16(&data[6]);
650 //TimeTaker t1("TOCLIENT_REMOVENODE");
652 // This will clear the cracking animation after digging
653 ((ClientMap&)m_env.getMap()).clearTempMod(p);
657 else if(command == TOCLIENT_ADDNODE)
659 if(datasize < 8 + MapNode::serializedLength(ser_version))
663 p.X = readS16(&data[2]);
664 p.Y = readS16(&data[4]);
665 p.Z = readS16(&data[6]);
667 //TimeTaker t1("TOCLIENT_ADDNODE");
670 n.deSerialize(&data[8], ser_version);
674 else if(command == TOCLIENT_BLOCKDATA)
676 // Ignore too small packet
681 p.X = readS16(&data[2]);
682 p.Y = readS16(&data[4]);
683 p.Z = readS16(&data[6]);
685 /*dout_client<<DTIME<<"Client: Thread: BLOCKDATA for ("
686 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
687 /*dstream<<DTIME<<"Client: Thread: BLOCKDATA for ("
688 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
690 std::string datastring((char*)&data[8], datasize-8);
691 std::istringstream istr(datastring, std::ios_base::binary);
697 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
700 sector = m_env.getMap().emergeSector(p2d);
702 v2s16 sp = sector->getPos();
705 dstream<<"ERROR: Got sector with getPos()="
706 <<"("<<sp.X<<","<<sp.Y<<"), tried to get"
707 <<"("<<p2d.X<<","<<p2d.Y<<")"<<std::endl;
711 //assert(sector->getPos() == p2d);
713 //TimeTaker timer("MapBlock deSerialize");
717 block = sector->getBlockNoCreate(p.Y);
719 Update an existing block
721 //dstream<<"Updating"<<std::endl;
722 block->deSerialize(istr, ser_version);
723 //block->setChangedFlag();
725 catch(InvalidPositionException &e)
730 //dstream<<"Creating new"<<std::endl;
731 block = new MapBlock(&m_env.getMap(), p);
732 block->deSerialize(istr, ser_version);
733 sector->insertBlock(block);
734 //block->setChangedFlag();
738 mod.type = NODEMOD_CHANGECONTENT;
739 mod.param = CONTENT_MESE;
740 block->setTempMod(v3s16(8,10,8), mod);
741 block->setTempMod(v3s16(8,9,8), mod);
742 block->setTempMod(v3s16(8,8,8), mod);
743 block->setTempMod(v3s16(8,7,8), mod);
744 block->setTempMod(v3s16(8,6,8), mod);*/
748 Well, this is a dumb way to do it, they should just
749 be drawn as separate objects. But the looks of them
750 can be tested this way.
755 mod.type = NODEMOD_CHANGECONTENT;
756 mod.param = CONTENT_CLOUD;
759 for(p2.X=3; p2.X<=13; p2.X++)
760 for(p2.Z=3; p2.Z<=13; p2.Z++)
762 block->setTempMod(p2, mod);
780 u32 replysize = 2+1+6;
781 SharedBuffer<u8> reply(replysize);
782 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
784 writeV3S16(&reply[3], p);
786 m_con.Send(PEER_ID_SERVER, 1, reply, true);
790 Update Mesh of this block and blocks at x-, y- and z-.
791 Environment should not be locked as it interlocks with the
792 main thread, from which is will want to retrieve textures.
795 //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
797 addUpdateMeshTaskWithEdge(p, true);
799 else if(command == TOCLIENT_PLAYERPOS)
801 dstream<<"WARNING: Received deprecated TOCLIENT_PLAYERPOS"
805 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
806 our_peer_id = m_con.GetPeerID();
808 // Cancel if we don't have a peer id
809 if(our_peer_id == PEER_ID_INEXISTENT){
810 dout_client<<DTIME<<"TOCLIENT_PLAYERPOS cancelled: "
817 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
819 u32 player_size = 2+12+12+4+4;
821 u32 player_count = (datasize-2) / player_size;
823 for(u32 i=0; i<player_count; i++)
825 u16 peer_id = readU16(&data[start]);
827 Player *player = m_env.getPlayer(peer_id);
829 // Skip if player doesn't exist
832 start += player_size;
836 // Skip if player is local player
837 if(player->isLocal())
839 start += player_size;
843 v3s32 ps = readV3S32(&data[start+2]);
844 v3s32 ss = readV3S32(&data[start+2+12]);
845 s32 pitch_i = readS32(&data[start+2+12+12]);
846 s32 yaw_i = readS32(&data[start+2+12+12+4]);
847 /*dstream<<"Client: got "
848 <<"pitch_i="<<pitch_i
849 <<" yaw_i="<<yaw_i<<std::endl;*/
850 f32 pitch = (f32)pitch_i / 100.0;
851 f32 yaw = (f32)yaw_i / 100.0;
852 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
853 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
854 player->setPosition(position);
855 player->setSpeed(speed);
856 player->setPitch(pitch);
859 /*dstream<<"Client: player "<<peer_id
861 <<" yaw="<<yaw<<std::endl;*/
863 start += player_size;
867 else if(command == TOCLIENT_PLAYERINFO)
871 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
872 our_peer_id = m_con.GetPeerID();
874 // Cancel if we don't have a peer id
875 if(our_peer_id == PEER_ID_INEXISTENT){
876 dout_client<<DTIME<<"TOCLIENT_PLAYERINFO cancelled: "
882 //dstream<<DTIME<<"Client: Server reports players:"<<std::endl;
885 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
887 u32 item_size = 2+PLAYERNAME_SIZE;
888 u32 player_count = (datasize-2) / item_size;
891 core::list<u16> players_alive;
892 for(u32 i=0; i<player_count; i++)
894 // Make sure the name ends in '\0'
895 data[start+2+20-1] = 0;
897 u16 peer_id = readU16(&data[start]);
899 players_alive.push_back(peer_id);
901 /*dstream<<DTIME<<"peer_id="<<peer_id
902 <<" name="<<((char*)&data[start+2])<<std::endl;*/
904 // Don't update the info of the local player
905 if(peer_id == our_peer_id)
911 Player *player = m_env.getPlayer(peer_id);
913 // Create a player if it doesn't exist
916 player = new RemotePlayer(
917 m_device->getSceneManager()->getRootSceneNode(),
920 player->peer_id = peer_id;
921 m_env.addPlayer(player);
922 dout_client<<DTIME<<"Client: Adding new player "
923 <<peer_id<<std::endl;
926 player->updateName((char*)&data[start+2]);
932 Remove those players from the environment that
933 weren't listed by the server.
935 //dstream<<DTIME<<"Removing dead players"<<std::endl;
936 core::list<Player*> players = m_env.getPlayers();
937 core::list<Player*>::Iterator ip;
938 for(ip=players.begin(); ip!=players.end(); ip++)
940 // Ingore local player
944 // Warn about a special case
945 if((*ip)->peer_id == 0)
947 dstream<<DTIME<<"WARNING: Client: Removing "
948 "dead player with id=0"<<std::endl;
951 bool is_alive = false;
952 core::list<u16>::Iterator i;
953 for(i=players_alive.begin(); i!=players_alive.end(); i++)
955 if((*ip)->peer_id == *i)
961 /*dstream<<DTIME<<"peer_id="<<((*ip)->peer_id)
962 <<" is_alive="<<is_alive<<std::endl;*/
965 dstream<<DTIME<<"Removing dead player "<<(*ip)->peer_id
967 m_env.removePlayer((*ip)->peer_id);
971 else if(command == TOCLIENT_SECTORMETA)
976 [3...] v2s16 pos + sector metadata
981 //dstream<<"Client received TOCLIENT_SECTORMETA"<<std::endl;
984 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
986 std::string datastring((char*)&data[2], datasize-2);
987 std::istringstream is(datastring, std::ios_base::binary);
991 is.read((char*)buf, 1);
992 u16 sector_count = readU8(buf);
994 //dstream<<"sector_count="<<sector_count<<std::endl;
996 for(u16 i=0; i<sector_count; i++)
999 is.read((char*)buf, 4);
1000 v2s16 pos = readV2S16(buf);
1001 /*dstream<<"Client: deserializing sector at "
1002 <<"("<<pos.X<<","<<pos.Y<<")"<<std::endl;*/
1004 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
1005 ((ClientMap&)m_env.getMap()).deSerializeSector(pos, is);
1009 else if(command == TOCLIENT_INVENTORY)
1014 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
1017 //TimeTaker t2("mutex locking", m_device);
1018 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1021 //TimeTaker t3("istringstream init", m_device);
1022 std::string datastring((char*)&data[2], datasize-2);
1023 std::istringstream is(datastring, std::ios_base::binary);
1026 //m_env.printPlayers(dstream);
1028 //TimeTaker t4("player get", m_device);
1029 Player *player = m_env.getLocalPlayer();
1030 assert(player != NULL);
1033 //TimeTaker t1("inventory.deSerialize()", m_device);
1034 player->inventory.deSerialize(is);
1037 m_inventory_updated = true;
1039 //dstream<<"Client got player inventory:"<<std::endl;
1040 //player->inventory.print(dstream);
1044 else if(command == TOCLIENT_OBJECTDATA)
1047 // Strip command word and create a stringstream
1048 std::string datastring((char*)&data[2], datasize-2);
1049 std::istringstream is(datastring, std::ios_base::binary);
1053 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1061 is.read((char*)buf, 2);
1062 u16 playercount = readU16(buf);
1064 for(u16 i=0; i<playercount; i++)
1066 is.read((char*)buf, 2);
1067 u16 peer_id = readU16(buf);
1068 is.read((char*)buf, 12);
1069 v3s32 p_i = readV3S32(buf);
1070 is.read((char*)buf, 12);
1071 v3s32 s_i = readV3S32(buf);
1072 is.read((char*)buf, 4);
1073 s32 pitch_i = readS32(buf);
1074 is.read((char*)buf, 4);
1075 s32 yaw_i = readS32(buf);
1077 Player *player = m_env.getPlayer(peer_id);
1079 // Skip if player doesn't exist
1085 // Skip if player is local player
1086 if(player->isLocal())
1091 f32 pitch = (f32)pitch_i / 100.0;
1092 f32 yaw = (f32)yaw_i / 100.0;
1093 v3f position((f32)p_i.X/100., (f32)p_i.Y/100., (f32)p_i.Z/100.);
1094 v3f speed((f32)s_i.X/100., (f32)s_i.Y/100., (f32)s_i.Z/100.);
1096 player->setPosition(position);
1097 player->setSpeed(speed);
1098 player->setPitch(pitch);
1099 player->setYaw(yaw);
1106 // Read active block count
1107 is.read((char*)buf, 2);
1108 u16 blockcount = readU16(buf);
1110 // Initialize delete queue with all active blocks
1111 core::map<v3s16, bool> abs_to_delete;
1112 for(core::map<v3s16, bool>::Iterator
1113 i = m_active_blocks.getIterator();
1114 i.atEnd() == false; i++)
1116 v3s16 p = i.getNode()->getKey();
1117 /*dstream<<"adding "
1118 <<"("<<p.x<<","<<p.y<<","<<p.z<<") "
1119 <<" to abs_to_delete"
1121 abs_to_delete.insert(p, true);
1124 /*dstream<<"Initial delete queue size: "<<abs_to_delete.size()
1127 for(u16 i=0; i<blockcount; i++)
1130 is.read((char*)buf, 6);
1131 v3s16 p = readV3S16(buf);
1132 // Get block from somewhere
1133 MapBlock *block = NULL;
1135 block = m_env.getMap().getBlockNoCreate(p);
1137 catch(InvalidPositionException &e)
1139 //TODO: Create a dummy block?
1143 dstream<<"WARNING: "
1144 <<"Could not get block at blockpos "
1145 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
1146 <<"in TOCLIENT_OBJECTDATA. Ignoring "
1147 <<"following block object data."
1152 /*dstream<<"Client updating objects for block "
1153 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1156 // Insert to active block list
1157 m_active_blocks.insert(p, true);
1159 // Remove from deletion queue
1160 if(abs_to_delete.find(p) != NULL)
1161 abs_to_delete.remove(p);
1164 Update objects of block
1166 NOTE: Be sure this is done in the main thread.
1168 block->updateObjects(is, m_server_ser_ver,
1169 m_device->getSceneManager(), m_env.getDayNightRatio());
1172 /*dstream<<"Final delete queue size: "<<abs_to_delete.size()
1175 // Delete objects of blocks in delete queue
1176 for(core::map<v3s16, bool>::Iterator
1177 i = abs_to_delete.getIterator();
1178 i.atEnd() == false; i++)
1180 v3s16 p = i.getNode()->getKey();
1183 MapBlock *block = m_env.getMap().getBlockNoCreate(p);
1186 block->clearObjects();
1187 // Remove from active blocks list
1188 m_active_blocks.remove(p);
1190 catch(InvalidPositionException &e)
1192 dstream<<"WARNAING: Client: "
1193 <<"Couldn't clear objects of active->inactive"
1195 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1196 <<" because block was not found"
1204 else if(command == TOCLIENT_TIME_OF_DAY)
1209 u16 time_of_day = readU16(&data[2]);
1210 time_of_day = time_of_day % 24000;
1211 //dstream<<"Client: time_of_day="<<time_of_day<<std::endl;
1219 m_env.setTimeOfDay(time_of_day);
1221 u32 dr = m_env.getDayNightRatio();
1223 dstream<<"Client: time_of_day="<<time_of_day
1229 else if(command == TOCLIENT_CHAT_MESSAGE)
1237 std::string datastring((char*)&data[2], datasize-2);
1238 std::istringstream is(datastring, std::ios_base::binary);
1241 is.read((char*)buf, 2);
1242 u16 len = readU16(buf);
1244 std::wstring message;
1245 for(u16 i=0; i<len; i++)
1247 is.read((char*)buf, 2);
1248 message += (wchar_t)readU16(buf);
1251 /*dstream<<"Client received chat message: "
1252 <<wide_to_narrow(message)<<std::endl;*/
1254 m_chat_queue.push_back(message);
1256 else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1258 //if(g_settings.getBool("enable_experimental"))
1262 u16 count of removed objects
1263 for all removed objects {
1266 u16 count of added objects
1267 for all added objects {
1270 u16 initialization data length
1271 string initialization data
1276 // Get all data except the command number
1277 std::string datastring((char*)&data[2], datasize-2);
1278 // Throw them in an istringstream
1279 std::istringstream is(datastring, std::ios_base::binary);
1283 // Read removed objects
1285 u16 removed_count = readU16((u8*)buf);
1286 for(u16 i=0; i<removed_count; i++)
1289 u16 id = readU16((u8*)buf);
1292 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1293 m_env.removeActiveObject(id);
1297 // Read added objects
1299 u16 added_count = readU16((u8*)buf);
1300 for(u16 i=0; i<added_count; i++)
1303 u16 id = readU16((u8*)buf);
1305 u8 type = readU8((u8*)buf);
1306 std::string data = deSerializeLongString(is);
1309 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1310 m_env.addActiveObject(id, type, data);
1315 else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1317 //if(g_settings.getBool("enable_experimental"))
1329 // Get all data except the command number
1330 std::string datastring((char*)&data[2], datasize-2);
1331 // Throw them in an istringstream
1332 std::istringstream is(datastring, std::ios_base::binary);
1334 while(is.eof() == false)
1338 u16 id = readU16((u8*)buf);
1342 u16 message_size = readU16((u8*)buf);
1343 std::string message;
1344 message.reserve(message_size);
1345 for(u16 i=0; i<message_size; i++)
1348 message.append(buf, 1);
1350 // Pass on to the environment
1352 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1353 m_env.processActiveObjectMessage(id, message);
1358 else if(command == TOCLIENT_HP)
1360 std::string datastring((char*)&data[2], datasize-2);
1361 std::istringstream is(datastring, std::ios_base::binary);
1362 Player *player = m_env.getLocalPlayer();
1363 assert(player != NULL);
1367 else if(command == TOCLIENT_MOVE_PLAYER)
1369 std::string datastring((char*)&data[2], datasize-2);
1370 std::istringstream is(datastring, std::ios_base::binary);
1371 Player *player = m_env.getLocalPlayer();
1372 assert(player != NULL);
1373 v3f pos = readV3F1000(is);
1374 f32 pitch = readF1000(is);
1375 f32 yaw = readF1000(is);
1376 player->setPosition(pos);
1377 /*player->setPitch(pitch);
1378 player->setYaw(yaw);*/
1380 dstream<<"Client got TOCLIENT_MOVE_PLAYER"
1381 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1387 Add to ClientEvent queue.
1388 This has to be sent to the main program because otherwise
1389 it would just force the pitch and yaw values to whatever
1390 the camera points to.
1393 event.type = CE_PLAYER_FORCE_MOVE;
1394 event.player_force_move.pitch = pitch;
1395 event.player_force_move.yaw = yaw;
1396 m_client_event_queue.push_back(event);
1398 // Ignore damage for a few seconds, so that the player doesn't
1399 // get damage from falling on ground
1400 m_ignore_damage_timer = 3.0;
1404 dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command "
1405 <<command<<std::endl;
1409 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1411 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1412 m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1415 void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
1416 v3s16 nodepos_oversurface, u16 item)
1418 if(connectedAndInitialized() == false){
1419 dout_client<<DTIME<<"Client::groundAction() "
1420 "cancelled (not connected)"
1429 [3] v3s16 nodepos_undersurface
1430 [9] v3s16 nodepos_abovesurface
1435 2: stop digging (all parameters ignored)
1436 3: digging completed
1438 u8 datasize = 2 + 1 + 6 + 6 + 2;
1439 SharedBuffer<u8> data(datasize);
1440 writeU16(&data[0], TOSERVER_GROUND_ACTION);
1441 writeU8(&data[2], action);
1442 writeV3S16(&data[3], nodepos_undersurface);
1443 writeV3S16(&data[9], nodepos_oversurface);
1444 writeU16(&data[15], item);
1445 Send(0, data, true);
1448 void Client::clickObject(u8 button, v3s16 blockpos, s16 id, u16 item)
1450 if(connectedAndInitialized() == false){
1451 dout_client<<DTIME<<"Client::clickObject() "
1452 "cancelled (not connected)"
1458 [0] u16 command=TOSERVER_CLICK_OBJECT
1459 [2] u8 button (0=left, 1=right)
1464 u8 datasize = 2 + 1 + 6 + 2 + 2;
1465 SharedBuffer<u8> data(datasize);
1466 writeU16(&data[0], TOSERVER_CLICK_OBJECT);
1467 writeU8(&data[2], button);
1468 writeV3S16(&data[3], blockpos);
1469 writeS16(&data[9], id);
1470 writeU16(&data[11], item);
1471 Send(0, data, true);
1474 void Client::clickActiveObject(u8 button, u16 id, u16 item)
1476 if(connectedAndInitialized() == false){
1477 dout_client<<DTIME<<"Client::clickActiveObject() "
1478 "cancelled (not connected)"
1486 [2] u8 button (0=left, 1=right)
1490 u8 datasize = 2 + 1 + 6 + 2 + 2;
1491 SharedBuffer<u8> data(datasize);
1492 writeU16(&data[0], TOSERVER_CLICK_ACTIVEOBJECT);
1493 writeU8(&data[2], button);
1494 writeU16(&data[3], id);
1495 writeU16(&data[5], item);
1496 Send(0, data, true);
1499 void Client::sendSignText(v3s16 blockpos, s16 id, std::string text)
1508 std::ostringstream os(std::ios_base::binary);
1512 writeU16(buf, TOSERVER_SIGNTEXT);
1513 os.write((char*)buf, 2);
1516 writeV3S16(buf, blockpos);
1517 os.write((char*)buf, 6);
1521 os.write((char*)buf, 2);
1523 u16 textlen = text.size();
1524 // Write text length
1525 writeS16(buf, textlen);
1526 os.write((char*)buf, 2);
1529 os.write((char*)text.c_str(), textlen);
1532 std::string s = os.str();
1533 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1535 Send(0, data, true);
1538 void Client::sendSignNodeText(v3s16 p, std::string text)
1546 std::ostringstream os(std::ios_base::binary);
1550 writeU16(buf, TOSERVER_SIGNNODETEXT);
1551 os.write((char*)buf, 2);
1555 os.write((char*)buf, 6);
1557 u16 textlen = text.size();
1558 // Write text length
1559 writeS16(buf, textlen);
1560 os.write((char*)buf, 2);
1563 os.write((char*)text.c_str(), textlen);
1566 std::string s = os.str();
1567 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1569 Send(0, data, true);
1572 void Client::sendInventoryAction(InventoryAction *a)
1574 std::ostringstream os(std::ios_base::binary);
1578 writeU16(buf, TOSERVER_INVENTORY_ACTION);
1579 os.write((char*)buf, 2);
1584 std::string s = os.str();
1585 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1587 Send(0, data, true);
1590 void Client::sendChatMessage(const std::wstring &message)
1592 std::ostringstream os(std::ios_base::binary);
1596 writeU16(buf, TOSERVER_CHAT_MESSAGE);
1597 os.write((char*)buf, 2);
1600 writeU16(buf, message.size());
1601 os.write((char*)buf, 2);
1604 for(u32 i=0; i<message.size(); i++)
1608 os.write((char*)buf, 2);
1612 std::string s = os.str();
1613 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1615 Send(0, data, true);
1618 void Client::sendChangePassword(const std::wstring oldpassword,
1619 const std::wstring newpassword)
1621 Player *player = m_env.getLocalPlayer();
1625 std::string playername = player->getName();
1626 std::string oldpwd = translatePassword(playername, oldpassword);
1627 std::string newpwd = translatePassword(playername, newpassword);
1629 std::ostringstream os(std::ios_base::binary);
1630 u8 buf[2+PASSWORD_SIZE*2];
1632 [0] u16 TOSERVER_PASSWORD
1633 [2] u8[28] old password
1634 [30] u8[28] new password
1637 writeU16(buf, TOSERVER_PASSWORD);
1638 for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1640 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1641 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1643 buf[2+PASSWORD_SIZE-1] = 0;
1644 buf[30+PASSWORD_SIZE-1] = 0;
1645 os.write((char*)buf, 2+PASSWORD_SIZE*2);
1648 std::string s = os.str();
1649 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1651 Send(0, data, true);
1655 void Client::sendDamage(u8 damage)
1657 DSTACK(__FUNCTION_NAME);
1658 std::ostringstream os(std::ios_base::binary);
1660 writeU16(os, TOSERVER_DAMAGE);
1661 writeU8(os, damage);
1664 std::string s = os.str();
1665 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1667 Send(0, data, true);
1670 void Client::sendPlayerPos()
1672 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1674 Player *myplayer = m_env.getLocalPlayer();
1675 if(myplayer == NULL)
1680 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1681 our_peer_id = m_con.GetPeerID();
1684 // Set peer id if not set already
1685 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1686 myplayer->peer_id = our_peer_id;
1687 // Check that an existing peer_id is the same as the connection's
1688 assert(myplayer->peer_id == our_peer_id);
1690 v3f pf = myplayer->getPosition();
1691 v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1692 v3f sf = myplayer->getSpeed();
1693 v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1694 s32 pitch = myplayer->getPitch() * 100;
1695 s32 yaw = myplayer->getYaw() * 100;
1700 [2] v3s32 position*100
1701 [2+12] v3s32 speed*100
1702 [2+12+12] s32 pitch*100
1703 [2+12+12+4] s32 yaw*100
1706 SharedBuffer<u8> data(2+12+12+4+4);
1707 writeU16(&data[0], TOSERVER_PLAYERPOS);
1708 writeV3S32(&data[2], position);
1709 writeV3S32(&data[2+12], speed);
1710 writeS32(&data[2+12+12], pitch);
1711 writeS32(&data[2+12+12+4], yaw);
1713 // Send as unreliable
1714 Send(0, data, false);
1717 void Client::removeNode(v3s16 p)
1719 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1721 core::map<v3s16, MapBlock*> modified_blocks;
1725 //TimeTaker t("removeNodeAndUpdate", m_device);
1726 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1728 catch(InvalidPositionException &e)
1732 for(core::map<v3s16, MapBlock * >::Iterator
1733 i = modified_blocks.getIterator();
1734 i.atEnd() == false; i++)
1736 v3s16 p = i.getNode()->getKey();
1737 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1738 addUpdateMeshTaskWithEdge(p);
1742 void Client::addNode(v3s16 p, MapNode n)
1744 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1746 TimeTaker timer1("Client::addNode()");
1748 core::map<v3s16, MapBlock*> modified_blocks;
1752 TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1753 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
1755 catch(InvalidPositionException &e)
1758 //TimeTaker timer2("Client::addNode(): updateMeshes");
1760 for(core::map<v3s16, MapBlock * >::Iterator
1761 i = modified_blocks.getIterator();
1762 i.atEnd() == false; i++)
1764 v3s16 p = i.getNode()->getKey();
1765 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1766 addUpdateMeshTaskWithEdge(p);
1770 void Client::updateCamera(v3f pos, v3f dir)
1772 m_env.getClientMap().updateCamera(pos, dir);
1773 camera_position = pos;
1774 camera_direction = dir;
1777 MapNode Client::getNode(v3s16 p)
1779 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1780 return m_env.getMap().getNode(p);
1783 NodeMetadata* Client::getNodeMetadata(v3s16 p)
1785 return m_env.getMap().getNodeMetadata(p);
1788 v3f Client::getPlayerPosition()
1790 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1791 LocalPlayer *player = m_env.getLocalPlayer();
1792 assert(player != NULL);
1793 return player->getPosition();
1796 void Client::setPlayerControl(PlayerControl &control)
1798 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1799 LocalPlayer *player = m_env.getLocalPlayer();
1800 assert(player != NULL);
1801 player->control = control;
1804 // Returns true if the inventory of the local player has been
1805 // updated from the server. If it is true, it is set to false.
1806 bool Client::getLocalInventoryUpdated()
1808 // m_inventory_updated is behind envlock
1809 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1810 bool updated = m_inventory_updated;
1811 m_inventory_updated = false;
1815 // Copies the inventory of the local player to parameter
1816 void Client::getLocalInventory(Inventory &dst)
1818 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1819 Player *player = m_env.getLocalPlayer();
1820 assert(player != NULL);
1821 dst = player->inventory;
1824 InventoryContext *Client::getInventoryContext()
1826 return &m_inventory_context;
1829 Inventory* Client::getInventory(InventoryContext *c, std::string id)
1831 if(id == "current_player")
1833 assert(c->current_player);
1834 return &(c->current_player->inventory);
1838 std::string id0 = fn.next(":");
1840 if(id0 == "nodemeta")
1843 p.X = stoi(fn.next(","));
1844 p.Y = stoi(fn.next(","));
1845 p.Z = stoi(fn.next(","));
1846 NodeMetadata* meta = getNodeMetadata(p);
1848 return meta->getInventory();
1849 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
1850 <<"no metadata found"<<std::endl;
1854 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
1857 void Client::inventoryAction(InventoryAction *a)
1859 sendInventoryAction(a);
1862 MapBlockObject * Client::getSelectedObject(
1864 v3f from_pos_f_on_map,
1865 core::line3d<f32> shootline_on_map
1868 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1870 core::array<DistanceSortedObject> objects;
1872 for(core::map<v3s16, bool>::Iterator
1873 i = m_active_blocks.getIterator();
1874 i.atEnd() == false; i++)
1876 v3s16 p = i.getNode()->getKey();
1878 MapBlock *block = NULL;
1881 block = m_env.getMap().getBlockNoCreate(p);
1883 catch(InvalidPositionException &e)
1888 // Calculate from_pos relative to block
1889 v3s16 block_pos_i_on_map = block->getPosRelative();
1890 v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
1891 v3f from_pos_f_on_block = from_pos_f_on_map - block_pos_f_on_map;
1893 block->getObjects(from_pos_f_on_block, max_d, objects);
1894 //block->getPseudoObjects(from_pos_f_on_block, max_d, objects);
1897 //dstream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
1900 // After this, the closest object is the first in the array.
1903 for(u32 i=0; i<objects.size(); i++)
1905 MapBlockObject *obj = objects[i].obj;
1906 MapBlock *block = obj->getBlock();
1908 // Calculate shootline relative to block
1909 v3s16 block_pos_i_on_map = block->getPosRelative();
1910 v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
1911 core::line3d<f32> shootline_on_block(
1912 shootline_on_map.start - block_pos_f_on_map,
1913 shootline_on_map.end - block_pos_f_on_map
1916 if(obj->isSelected(shootline_on_block))
1918 //dstream<<"Returning selected object"<<std::endl;
1923 //dstream<<"No object selected; returning NULL."<<std::endl;
1927 ClientActiveObject * Client::getSelectedActiveObject(
1929 v3f from_pos_f_on_map,
1930 core::line3d<f32> shootline_on_map
1933 core::array<DistanceSortedActiveObject> objects;
1935 m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
1937 //dstream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
1940 // After this, the closest object is the first in the array.
1943 for(u32 i=0; i<objects.size(); i++)
1945 ClientActiveObject *obj = objects[i].obj;
1947 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
1948 if(selection_box == NULL)
1951 v3f pos = obj->getPosition();
1953 core::aabbox3d<f32> offsetted_box(
1954 selection_box->MinEdge + pos,
1955 selection_box->MaxEdge + pos
1958 if(offsetted_box.intersectsWithLine(shootline_on_map))
1960 //dstream<<"Returning selected object"<<std::endl;
1965 //dstream<<"No object selected; returning NULL."<<std::endl;
1969 void Client::printDebugInfo(std::ostream &os)
1971 //JMutexAutoLock lock1(m_fetchblock_mutex);
1972 /*JMutexAutoLock lock2(m_incoming_queue_mutex);
1974 os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
1975 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
1976 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
1980 /*s32 Client::getDayNightIndex()
1982 assert(m_daynight_i >= 0 && m_daynight_i < DAYNIGHT_CACHE_COUNT);
1983 return m_daynight_i;
1986 u32 Client::getDayNightRatio()
1988 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1989 return m_env.getDayNightRatio();
1994 Player *player = m_env.getLocalPlayer();
1995 assert(player != NULL);
1999 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
2001 /*dstream<<"Client::addUpdateMeshTask(): "
2002 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2005 MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2010 Create a task to update the mesh of the block
2013 MeshMakeData *data = new MeshMakeData;
2016 //TimeTaker timer("data fill");
2018 data->fill(getDayNightRatio(), b);
2022 //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2024 // Add task to queue
2025 m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server);
2027 /*dstream<<"Mesh update input queue size is "
2028 <<m_mesh_update_thread.m_queue_in.size()
2032 // Temporary test: make mesh directly in here
2034 //TimeTaker timer("make mesh");
2036 scene::SMesh *mesh_new = NULL;
2037 mesh_new = makeMapBlockMesh(data);
2038 b->replaceMesh(mesh_new);
2043 b->setMeshExpired(false);
2046 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
2050 dstream<<"Client::addUpdateMeshTaskWithEdge(): "
2051 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2056 v3s16 p = blockpos + v3s16(0,0,0);
2057 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2058 addUpdateMeshTask(p, ack_to_server);
2060 catch(InvalidPositionException &e){}
2063 v3s16 p = blockpos + v3s16(-1,0,0);
2064 addUpdateMeshTask(p);
2066 catch(InvalidPositionException &e){}
2068 v3s16 p = blockpos + v3s16(0,-1,0);
2069 addUpdateMeshTask(p);
2071 catch(InvalidPositionException &e){}
2073 v3s16 p = blockpos + v3s16(0,0,-1);
2074 addUpdateMeshTask(p);
2076 catch(InvalidPositionException &e){}
2079 ClientEvent Client::getClientEvent()
2081 if(m_client_event_queue.size() == 0)
2084 event.type = CE_NONE;
2087 return m_client_event_queue.pop_front();