3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "clientserver.h"
24 #include "jmutexautolock.h"
28 #include "mapsector.h"
29 #include "mapblock_mesh.h"
38 QueuedMeshUpdate::QueuedMeshUpdate():
41 ack_block_to_server(false)
45 QueuedMeshUpdate::~QueuedMeshUpdate()
55 MeshUpdateQueue::MeshUpdateQueue()
60 MeshUpdateQueue::~MeshUpdateQueue()
62 JMutexAutoLock lock(m_mutex);
64 core::list<QueuedMeshUpdate*>::Iterator i;
65 for(i=m_queue.begin(); i!=m_queue.end(); i++)
67 QueuedMeshUpdate *q = *i;
73 peer_id=0 adds with nobody to send to
75 void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server)
77 DSTACK(__FUNCTION_NAME);
81 JMutexAutoLock lock(m_mutex);
84 Find if block is already in queue.
85 If it is, update the data and quit.
87 core::list<QueuedMeshUpdate*>::Iterator i;
88 for(i=m_queue.begin(); i!=m_queue.end(); i++)
90 QueuedMeshUpdate *q = *i;
96 if(ack_block_to_server)
97 q->ack_block_to_server = true;
105 QueuedMeshUpdate *q = new QueuedMeshUpdate;
108 q->ack_block_to_server = ack_block_to_server;
109 m_queue.push_back(q);
112 // Returned pointer must be deleted
113 // Returns NULL if queue is empty
114 QueuedMeshUpdate * MeshUpdateQueue::pop()
116 JMutexAutoLock lock(m_mutex);
118 core::list<QueuedMeshUpdate*>::Iterator i = m_queue.begin();
119 if(i == m_queue.end())
121 QueuedMeshUpdate *q = *i;
130 void * MeshUpdateThread::Thread()
134 DSTACK(__FUNCTION_NAME);
136 BEGIN_DEBUG_EXCEPTION_HANDLER
140 /*// Wait for output queue to flush.
141 // Allow 2 in queue, this makes less frametime jitter.
142 // Umm actually, there is no much difference
143 if(m_queue_out.size() >= 2)
149 QueuedMeshUpdate *q = m_queue_in.pop();
156 ScopeProfiler sp(g_profiler, "mesh make");
158 scene::SMesh *mesh_new = NULL;
159 mesh_new = makeMapBlockMesh(q->data);
164 r.ack_block_to_server = q->ack_block_to_server;
166 /*dstream<<"MeshUpdateThread: Processed "
167 <<"("<<q->p.X<<","<<q->p.Y<<","<<q->p.Z<<")"
170 m_queue_out.push_back(r);
175 END_DEBUG_EXCEPTION_HANDLER
181 IrrlichtDevice *device,
182 const char *playername,
183 std::string password,
184 MapDrawControl &control):
185 m_mesh_update_thread(),
187 new ClientMap(this, control,
188 device->getSceneManager()->getRootSceneNode(),
189 device->getSceneManager(), 666),
190 device->getSceneManager()
192 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
194 m_server_ser_ver(SER_FMT_VER_INVALID),
195 m_inventory_updated(false),
198 m_password(password),
199 m_access_denied(false)
201 m_packetcounter_timer = 0.0;
202 //m_delete_unused_sectors_timer = 0.0;
203 m_connection_reinit_timer = 0.0;
204 m_avg_rtt_timer = 0.0;
205 m_playerpos_send_timer = 0.0;
206 m_ignore_damage_timer = 0.0;
208 //m_env_mutex.Init();
209 //m_con_mutex.Init();
211 m_mesh_update_thread.Start();
217 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
219 Player *player = new LocalPlayer();
221 player->updateName(playername);
223 m_env.addPlayer(player);
225 // Initialize player in the inventory context
226 m_inventory_context.current_player = player;
233 //JMutexAutoLock conlock(m_con_mutex); //bulk comment-out
237 m_mesh_update_thread.setRun(false);
238 while(m_mesh_update_thread.IsRunning())
242 void Client::connect(Address address)
244 DSTACK(__FUNCTION_NAME);
245 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
246 m_con.setTimeoutMs(0);
247 m_con.Connect(address);
250 bool Client::connectedAndInitialized()
252 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
254 if(m_con.Connected() == false)
257 if(m_server_ser_ver == SER_FMT_VER_INVALID)
263 void Client::step(float dtime)
265 DSTACK(__FUNCTION_NAME);
271 if(m_ignore_damage_timer > dtime)
272 m_ignore_damage_timer -= dtime;
274 m_ignore_damage_timer = 0.0;
276 //dstream<<"Client steps "<<dtime<<std::endl;
279 //TimeTaker timer("ReceiveAll()", m_device);
285 //TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device);
287 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
288 m_con.RunTimeouts(dtime);
295 float &counter = m_packetcounter_timer;
301 dout_client<<"Client packetcounter (20s):"<<std::endl;
302 m_packetcounter.print(dout_client);
303 m_packetcounter.clear();
307 // Get connection status
308 bool connected = connectedAndInitialized();
313 Delete unused sectors
315 NOTE: This jams the game for a while because deleting sectors
319 float &counter = m_delete_unused_sectors_timer;
327 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
329 core::list<v3s16> deleted_blocks;
331 float delete_unused_sectors_timeout =
332 g_settings->getFloat("client_delete_unused_sectors_timeout");
334 // Delete sector blocks
335 /*u32 num = m_env.getMap().unloadUnusedData
336 (delete_unused_sectors_timeout,
337 true, &deleted_blocks);*/
339 // Delete whole sectors
340 m_env.getMap().unloadUnusedData
341 (delete_unused_sectors_timeout,
344 if(deleted_blocks.size() > 0)
346 /*dstream<<DTIME<<"Client: Deleted blocks of "<<num
347 <<" unused sectors"<<std::endl;*/
348 /*dstream<<DTIME<<"Client: Deleted "<<num
349 <<" unused sectors"<<std::endl;*/
355 // Env is locked so con can be locked.
356 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
358 core::list<v3s16>::Iterator i = deleted_blocks.begin();
359 core::list<v3s16> sendlist;
362 if(sendlist.size() == 255 || i == deleted_blocks.end())
364 if(sendlist.size() == 0)
373 u32 replysize = 2+1+6*sendlist.size();
374 SharedBuffer<u8> reply(replysize);
375 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
376 reply[2] = sendlist.size();
378 for(core::list<v3s16>::Iterator
379 j = sendlist.begin();
380 j != sendlist.end(); j++)
382 writeV3S16(&reply[2+1+6*k], *j);
385 m_con.Send(PEER_ID_SERVER, 1, reply, true);
387 if(i == deleted_blocks.end())
393 sendlist.push_back(*i);
401 if(connected == false)
403 float &counter = m_connection_reinit_timer;
409 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
411 Player *myplayer = m_env.getLocalPlayer();
412 assert(myplayer != NULL);
414 // Send TOSERVER_INIT
415 // [0] u16 TOSERVER_INIT
416 // [2] u8 SER_FMT_VER_HIGHEST
417 // [3] u8[20] player_name
418 // [23] u8[28] password (new in some version)
419 // [51] u16 client network protocol version (new in some version)
420 SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2);
421 writeU16(&data[0], TOSERVER_INIT);
422 writeU8(&data[2], SER_FMT_VER_HIGHEST);
424 memset((char*)&data[3], 0, PLAYERNAME_SIZE);
425 snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
427 /*dstream<<"Client: sending initial password hash: \""<<m_password<<"\""
430 memset((char*)&data[23], 0, PASSWORD_SIZE);
431 snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
433 // This should be incremented in each version
434 writeU16(&data[51], 2);
436 // Send as unreliable
437 Send(0, data, false);
440 // Not connected, return
445 Do stuff if connected
449 Run Map's timers and unload unused data
451 const float map_timer_and_unload_dtime = 5.25;
452 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
454 ScopeProfiler sp(g_profiler, "Client: map timer and unload");
455 core::list<v3s16> deleted_blocks;
456 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
457 g_settings->getFloat("client_unload_unused_data_timeout"),
460 /*if(deleted_blocks.size() > 0)
461 dstream<<"Client: Unloaded "<<deleted_blocks.size()
462 <<" unused blocks"<<std::endl;*/
466 NOTE: This loop is intentionally iterated the way it is.
469 core::list<v3s16>::Iterator i = deleted_blocks.begin();
470 core::list<v3s16> sendlist;
473 if(sendlist.size() == 255 || i == deleted_blocks.end())
475 if(sendlist.size() == 0)
484 u32 replysize = 2+1+6*sendlist.size();
485 SharedBuffer<u8> reply(replysize);
486 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
487 reply[2] = sendlist.size();
489 for(core::list<v3s16>::Iterator
490 j = sendlist.begin();
491 j != sendlist.end(); j++)
493 writeV3S16(&reply[2+1+6*k], *j);
496 m_con.Send(PEER_ID_SERVER, 1, reply, true);
498 if(i == deleted_blocks.end())
504 sendlist.push_back(*i);
514 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
516 // Control local player (0ms)
517 LocalPlayer *player = m_env.getLocalPlayer();
518 assert(player != NULL);
519 player->applyControl(dtime);
521 //TimeTaker envtimer("env step", m_device);
530 ClientEnvEvent event = m_env.getClientEvent();
531 if(event.type == CEE_NONE)
535 else if(event.type == CEE_PLAYER_DAMAGE)
537 if(m_ignore_damage_timer <= 0)
539 u8 damage = event.player_damage.amount;
542 // Add to ClientEvent queue
544 event.type = CE_PLAYER_DAMAGE;
545 event.player_damage.amount = damage;
546 m_client_event_queue.push_back(event);
556 float &counter = m_avg_rtt_timer;
561 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
562 // connectedAndInitialized() is true, peer exists.
563 con::Peer *peer = m_con.GetPeer(PEER_ID_SERVER);
564 dstream<<DTIME<<"Client: avg_rtt="<<peer->avg_rtt<<std::endl;
569 Send player position to server
572 float &counter = m_playerpos_send_timer;
582 Replace updated meshes
585 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
587 //TimeTaker timer("** Processing mesh update result queue");
590 /*dstream<<"Mesh update result queue size is "
591 <<m_mesh_update_thread.m_queue_out.size()
594 while(m_mesh_update_thread.m_queue_out.size() > 0)
596 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
597 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
600 block->replaceMesh(r.mesh);
602 if(r.ack_block_to_server)
604 /*dstream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
605 <<","<<r.p.Z<<")"<<std::endl;*/
616 u32 replysize = 2+1+6;
617 SharedBuffer<u8> reply(replysize);
618 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
620 writeV3S16(&reply[3], r.p);
622 m_con.Send(PEER_ID_SERVER, 1, reply, true);
628 // Virtual methods from con::PeerHandler
629 void Client::peerAdded(con::Peer *peer)
631 derr_client<<"Client::peerAdded(): peer->id="
632 <<peer->id<<std::endl;
634 void Client::deletingPeer(con::Peer *peer, bool timeout)
636 derr_client<<"Client::deletingPeer(): "
637 "Server Peer is getting deleted "
638 <<"(timeout="<<timeout<<")"<<std::endl;
641 void Client::ReceiveAll()
643 DSTACK(__FUNCTION_NAME);
649 catch(con::NoIncomingDataException &e)
653 catch(con::InvalidIncomingDataException &e)
655 dout_client<<DTIME<<"Client::ReceiveAll(): "
656 "InvalidIncomingDataException: what()="
657 <<e.what()<<std::endl;
662 void Client::Receive()
664 DSTACK(__FUNCTION_NAME);
665 u32 data_maxsize = 200000;
666 Buffer<u8> data(data_maxsize);
670 //TimeTaker t1("con mutex and receive", m_device);
671 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
672 datasize = m_con.Receive(sender_peer_id, *data, data_maxsize);
674 //TimeTaker t1("ProcessData", m_device);
675 ProcessData(*data, datasize, sender_peer_id);
679 sender_peer_id given to this shall be quaranteed to be a valid peer
681 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
683 DSTACK(__FUNCTION_NAME);
685 // Ignore packets that don't even fit a command
688 m_packetcounter.add(60000);
692 ToClientCommand command = (ToClientCommand)readU16(&data[0]);
694 //dstream<<"Client: received command="<<command<<std::endl;
695 m_packetcounter.add((u16)command);
698 If this check is removed, be sure to change the queue
699 system to know the ids
701 if(sender_peer_id != PEER_ID_SERVER)
703 dout_client<<DTIME<<"Client::ProcessData(): Discarding data not "
704 "coming from server: peer_id="<<sender_peer_id
711 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
712 // All data is coming from the server
713 // PeerNotFoundException is handled by caller.
714 peer = m_con.GetPeer(PEER_ID_SERVER);
717 u8 ser_version = m_server_ser_ver;
719 //dstream<<"Client received command="<<(int)command<<std::endl;
721 if(command == TOCLIENT_INIT)
726 u8 deployed = data[2];
728 dout_client<<DTIME<<"Client: TOCLIENT_INIT received with "
729 "deployed="<<((int)deployed&0xff)<<std::endl;
731 if(deployed < SER_FMT_VER_LOWEST
732 || deployed > SER_FMT_VER_HIGHEST)
734 derr_client<<DTIME<<"Client: TOCLIENT_INIT: Server sent "
735 <<"unsupported ser_fmt_ver"<<std::endl;
739 m_server_ser_ver = deployed;
741 // Get player position
742 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
743 if(datasize >= 2+1+6)
744 playerpos_s16 = readV3S16(&data[2+1]);
745 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
748 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
750 // Set player position
751 Player *player = m_env.getLocalPlayer();
752 assert(player != NULL);
753 player->setPosition(playerpos_f);
756 if(datasize >= 2+1+6+8)
759 m_map_seed = readU64(&data[2+1+6]);
760 dstream<<"Client: received map seed: "<<m_map_seed<<std::endl;
765 SharedBuffer<u8> reply(replysize);
766 writeU16(&reply[0], TOSERVER_INIT2);
768 m_con.Send(PEER_ID_SERVER, 1, reply, true);
773 if(command == TOCLIENT_ACCESS_DENIED)
775 // The server didn't like our password. Note, this needs
776 // to be processed even if the serialisation format has
777 // not been agreed yet, the same as TOCLIENT_INIT.
778 m_access_denied = true;
779 m_access_denied_reason = L"Unknown";
782 std::string datastring((char*)&data[2], datasize-2);
783 std::istringstream is(datastring, std::ios_base::binary);
784 m_access_denied_reason = deSerializeWideString(is);
789 if(ser_version == SER_FMT_VER_INVALID)
791 dout_client<<DTIME<<"WARNING: Client: Server serialization"
792 " format invalid or not initialized."
793 " Skipping incoming command="<<command<<std::endl;
797 // Just here to avoid putting the two if's together when
798 // making some copypasta
801 if(command == TOCLIENT_REMOVENODE)
806 p.X = readS16(&data[2]);
807 p.Y = readS16(&data[4]);
808 p.Z = readS16(&data[6]);
810 //TimeTaker t1("TOCLIENT_REMOVENODE");
812 // This will clear the cracking animation after digging
813 ((ClientMap&)m_env.getMap()).clearTempMod(p);
817 else if(command == TOCLIENT_ADDNODE)
819 if(datasize < 8 + MapNode::serializedLength(ser_version))
823 p.X = readS16(&data[2]);
824 p.Y = readS16(&data[4]);
825 p.Z = readS16(&data[6]);
827 //TimeTaker t1("TOCLIENT_ADDNODE");
830 n.deSerialize(&data[8], ser_version);
834 else if(command == TOCLIENT_BLOCKDATA)
836 // Ignore too small packet
841 p.X = readS16(&data[2]);
842 p.Y = readS16(&data[4]);
843 p.Z = readS16(&data[6]);
845 /*dout_client<<DTIME<<"Client: Thread: BLOCKDATA for ("
846 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
847 /*dstream<<DTIME<<"Client: Thread: BLOCKDATA for ("
848 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
850 std::string datastring((char*)&data[8], datasize-8);
851 std::istringstream istr(datastring, std::ios_base::binary);
857 sector = m_env.getMap().emergeSector(p2d);
859 assert(sector->getPos() == p2d);
861 //TimeTaker timer("MapBlock deSerialize");
864 block = sector->getBlockNoCreateNoEx(p.Y);
868 Update an existing block
870 //dstream<<"Updating"<<std::endl;
871 block->deSerialize(istr, ser_version);
878 //dstream<<"Creating new"<<std::endl;
879 block = new MapBlock(&m_env.getMap(), p);
880 block->deSerialize(istr, ser_version);
881 sector->insertBlock(block);
885 mod.type = NODEMOD_CHANGECONTENT;
886 mod.param = CONTENT_MESE;
887 block->setTempMod(v3s16(8,10,8), mod);
888 block->setTempMod(v3s16(8,9,8), mod);
889 block->setTempMod(v3s16(8,8,8), mod);
890 block->setTempMod(v3s16(8,7,8), mod);
891 block->setTempMod(v3s16(8,6,8), mod);*/
905 u32 replysize = 2+1+6;
906 SharedBuffer<u8> reply(replysize);
907 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
909 writeV3S16(&reply[3], p);
911 m_con.Send(PEER_ID_SERVER, 1, reply, true);
915 Update Mesh of this block and blocks at x-, y- and z-.
916 Environment should not be locked as it interlocks with the
917 main thread, from which is will want to retrieve textures.
920 //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
922 Add it to mesh update queue and set it to be acknowledged after update.
924 //std::cerr<<"Adding mesh update task for received block"<<std::endl;
925 addUpdateMeshTaskWithEdge(p, true);
927 else if(command == TOCLIENT_PLAYERPOS)
929 dstream<<"WARNING: Received deprecated TOCLIENT_PLAYERPOS"
933 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
934 our_peer_id = m_con.GetPeerID();
936 // Cancel if we don't have a peer id
937 if(our_peer_id == PEER_ID_INEXISTENT){
938 dout_client<<DTIME<<"TOCLIENT_PLAYERPOS cancelled: "
945 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
947 u32 player_size = 2+12+12+4+4;
949 u32 player_count = (datasize-2) / player_size;
951 for(u32 i=0; i<player_count; i++)
953 u16 peer_id = readU16(&data[start]);
955 Player *player = m_env.getPlayer(peer_id);
957 // Skip if player doesn't exist
960 start += player_size;
964 // Skip if player is local player
965 if(player->isLocal())
967 start += player_size;
971 v3s32 ps = readV3S32(&data[start+2]);
972 v3s32 ss = readV3S32(&data[start+2+12]);
973 s32 pitch_i = readS32(&data[start+2+12+12]);
974 s32 yaw_i = readS32(&data[start+2+12+12+4]);
975 /*dstream<<"Client: got "
976 <<"pitch_i="<<pitch_i
977 <<" yaw_i="<<yaw_i<<std::endl;*/
978 f32 pitch = (f32)pitch_i / 100.0;
979 f32 yaw = (f32)yaw_i / 100.0;
980 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
981 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
982 player->setPosition(position);
983 player->setSpeed(speed);
984 player->setPitch(pitch);
987 /*dstream<<"Client: player "<<peer_id
989 <<" yaw="<<yaw<<std::endl;*/
991 start += player_size;
995 else if(command == TOCLIENT_PLAYERINFO)
999 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1000 our_peer_id = m_con.GetPeerID();
1002 // Cancel if we don't have a peer id
1003 if(our_peer_id == PEER_ID_INEXISTENT){
1004 dout_client<<DTIME<<"TOCLIENT_PLAYERINFO cancelled: "
1005 "we have no peer id"
1010 //dstream<<DTIME<<"Client: Server reports players:"<<std::endl;
1013 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1015 u32 item_size = 2+PLAYERNAME_SIZE;
1016 u32 player_count = (datasize-2) / item_size;
1019 core::list<u16> players_alive;
1020 for(u32 i=0; i<player_count; i++)
1022 // Make sure the name ends in '\0'
1023 data[start+2+20-1] = 0;
1025 u16 peer_id = readU16(&data[start]);
1027 players_alive.push_back(peer_id);
1029 /*dstream<<DTIME<<"peer_id="<<peer_id
1030 <<" name="<<((char*)&data[start+2])<<std::endl;*/
1032 // Don't update the info of the local player
1033 if(peer_id == our_peer_id)
1039 Player *player = m_env.getPlayer(peer_id);
1041 // Create a player if it doesn't exist
1044 player = new RemotePlayer(
1045 m_device->getSceneManager()->getRootSceneNode(),
1048 player->peer_id = peer_id;
1049 m_env.addPlayer(player);
1050 dout_client<<DTIME<<"Client: Adding new player "
1051 <<peer_id<<std::endl;
1054 player->updateName((char*)&data[start+2]);
1060 Remove those players from the environment that
1061 weren't listed by the server.
1063 //dstream<<DTIME<<"Removing dead players"<<std::endl;
1064 core::list<Player*> players = m_env.getPlayers();
1065 core::list<Player*>::Iterator ip;
1066 for(ip=players.begin(); ip!=players.end(); ip++)
1068 // Ingore local player
1069 if((*ip)->isLocal())
1072 // Warn about a special case
1073 if((*ip)->peer_id == 0)
1075 dstream<<DTIME<<"WARNING: Client: Removing "
1076 "dead player with id=0"<<std::endl;
1079 bool is_alive = false;
1080 core::list<u16>::Iterator i;
1081 for(i=players_alive.begin(); i!=players_alive.end(); i++)
1083 if((*ip)->peer_id == *i)
1089 /*dstream<<DTIME<<"peer_id="<<((*ip)->peer_id)
1090 <<" is_alive="<<is_alive<<std::endl;*/
1093 dstream<<DTIME<<"Removing dead player "<<(*ip)->peer_id
1095 m_env.removePlayer((*ip)->peer_id);
1099 else if(command == TOCLIENT_SECTORMETA)
1101 dstream<<"Client received DEPRECATED TOCLIENT_SECTORMETA"<<std::endl;
1106 [3...] v2s16 pos + sector metadata
1111 //dstream<<"Client received TOCLIENT_SECTORMETA"<<std::endl;
1114 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1116 std::string datastring((char*)&data[2], datasize-2);
1117 std::istringstream is(datastring, std::ios_base::binary);
1121 is.read((char*)buf, 1);
1122 u16 sector_count = readU8(buf);
1124 //dstream<<"sector_count="<<sector_count<<std::endl;
1126 for(u16 i=0; i<sector_count; i++)
1129 is.read((char*)buf, 4);
1130 v2s16 pos = readV2S16(buf);
1131 /*dstream<<"Client: deserializing sector at "
1132 <<"("<<pos.X<<","<<pos.Y<<")"<<std::endl;*/
1134 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
1135 ((ClientMap&)m_env.getMap()).deSerializeSector(pos, is);
1140 else if(command == TOCLIENT_INVENTORY)
1145 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
1148 //TimeTaker t2("mutex locking", m_device);
1149 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1152 //TimeTaker t3("istringstream init", m_device);
1153 std::string datastring((char*)&data[2], datasize-2);
1154 std::istringstream is(datastring, std::ios_base::binary);
1157 //m_env.printPlayers(dstream);
1159 //TimeTaker t4("player get", m_device);
1160 Player *player = m_env.getLocalPlayer();
1161 assert(player != NULL);
1164 //TimeTaker t1("inventory.deSerialize()", m_device);
1165 player->inventory.deSerialize(is);
1168 m_inventory_updated = true;
1170 //dstream<<"Client got player inventory:"<<std::endl;
1171 //player->inventory.print(dstream);
1175 else if(command == TOCLIENT_OBJECTDATA)
1177 // Strip command word and create a stringstream
1178 std::string datastring((char*)&data[2], datasize-2);
1179 std::istringstream is(datastring, std::ios_base::binary);
1187 is.read((char*)buf, 2);
1188 u16 playercount = readU16(buf);
1190 for(u16 i=0; i<playercount; i++)
1192 is.read((char*)buf, 2);
1193 u16 peer_id = readU16(buf);
1194 is.read((char*)buf, 12);
1195 v3s32 p_i = readV3S32(buf);
1196 is.read((char*)buf, 12);
1197 v3s32 s_i = readV3S32(buf);
1198 is.read((char*)buf, 4);
1199 s32 pitch_i = readS32(buf);
1200 is.read((char*)buf, 4);
1201 s32 yaw_i = readS32(buf);
1203 Player *player = m_env.getPlayer(peer_id);
1205 // Skip if player doesn't exist
1211 // Skip if player is local player
1212 if(player->isLocal())
1217 f32 pitch = (f32)pitch_i / 100.0;
1218 f32 yaw = (f32)yaw_i / 100.0;
1219 v3f position((f32)p_i.X/100., (f32)p_i.Y/100., (f32)p_i.Z/100.);
1220 v3f speed((f32)s_i.X/100., (f32)s_i.Y/100., (f32)s_i.Z/100.);
1222 player->setPosition(position);
1223 player->setSpeed(speed);
1224 player->setPitch(pitch);
1225 player->setYaw(yaw);
1230 NOTE: Deprecated stuff
1233 // Read active block count
1234 u16 blockcount = readU16(is);
1235 if(blockcount != 0){
1236 dstream<<"WARNING: TOCLIENT_OBJECTDATA: blockcount != 0 "
1237 "not supported"<<std::endl;
1241 else if(command == TOCLIENT_TIME_OF_DAY)
1246 u16 time_of_day = readU16(&data[2]);
1247 time_of_day = time_of_day % 24000;
1248 //dstream<<"Client: time_of_day="<<time_of_day<<std::endl;
1256 m_env.setTimeOfDay(time_of_day);
1258 u32 dr = m_env.getDayNightRatio();
1260 dstream<<"Client: time_of_day="<<time_of_day
1266 else if(command == TOCLIENT_CHAT_MESSAGE)
1274 std::string datastring((char*)&data[2], datasize-2);
1275 std::istringstream is(datastring, std::ios_base::binary);
1278 is.read((char*)buf, 2);
1279 u16 len = readU16(buf);
1281 std::wstring message;
1282 for(u16 i=0; i<len; i++)
1284 is.read((char*)buf, 2);
1285 message += (wchar_t)readU16(buf);
1288 /*dstream<<"Client received chat message: "
1289 <<wide_to_narrow(message)<<std::endl;*/
1291 m_chat_queue.push_back(message);
1293 else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1295 //if(g_settings->getBool("enable_experimental"))
1299 u16 count of removed objects
1300 for all removed objects {
1303 u16 count of added objects
1304 for all added objects {
1307 u32 initialization data length
1308 string initialization data
1313 // Get all data except the command number
1314 std::string datastring((char*)&data[2], datasize-2);
1315 // Throw them in an istringstream
1316 std::istringstream is(datastring, std::ios_base::binary);
1320 // Read removed objects
1322 u16 removed_count = readU16((u8*)buf);
1323 for(u16 i=0; i<removed_count; i++)
1326 u16 id = readU16((u8*)buf);
1329 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1330 m_env.removeActiveObject(id);
1334 // Read added objects
1336 u16 added_count = readU16((u8*)buf);
1337 for(u16 i=0; i<added_count; i++)
1340 u16 id = readU16((u8*)buf);
1342 u8 type = readU8((u8*)buf);
1343 std::string data = deSerializeLongString(is);
1346 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1347 m_env.addActiveObject(id, type, data);
1352 else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1354 //if(g_settings->getBool("enable_experimental"))
1366 // Get all data except the command number
1367 std::string datastring((char*)&data[2], datasize-2);
1368 // Throw them in an istringstream
1369 std::istringstream is(datastring, std::ios_base::binary);
1371 while(is.eof() == false)
1375 u16 id = readU16((u8*)buf);
1379 u16 message_size = readU16((u8*)buf);
1380 std::string message;
1381 message.reserve(message_size);
1382 for(u16 i=0; i<message_size; i++)
1385 message.append(buf, 1);
1387 // Pass on to the environment
1389 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1390 m_env.processActiveObjectMessage(id, message);
1395 else if(command == TOCLIENT_HP)
1397 std::string datastring((char*)&data[2], datasize-2);
1398 std::istringstream is(datastring, std::ios_base::binary);
1399 Player *player = m_env.getLocalPlayer();
1400 assert(player != NULL);
1404 else if(command == TOCLIENT_MOVE_PLAYER)
1406 std::string datastring((char*)&data[2], datasize-2);
1407 std::istringstream is(datastring, std::ios_base::binary);
1408 Player *player = m_env.getLocalPlayer();
1409 assert(player != NULL);
1410 v3f pos = readV3F1000(is);
1411 f32 pitch = readF1000(is);
1412 f32 yaw = readF1000(is);
1413 player->setPosition(pos);
1414 /*player->setPitch(pitch);
1415 player->setYaw(yaw);*/
1417 dstream<<"Client got TOCLIENT_MOVE_PLAYER"
1418 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1424 Add to ClientEvent queue.
1425 This has to be sent to the main program because otherwise
1426 it would just force the pitch and yaw values to whatever
1427 the camera points to.
1430 event.type = CE_PLAYER_FORCE_MOVE;
1431 event.player_force_move.pitch = pitch;
1432 event.player_force_move.yaw = yaw;
1433 m_client_event_queue.push_back(event);
1435 // Ignore damage for a few seconds, so that the player doesn't
1436 // get damage from falling on ground
1437 m_ignore_damage_timer = 3.0;
1439 else if(command == TOCLIENT_PLAYERITEM)
1441 std::string datastring((char*)&data[2], datasize-2);
1442 std::istringstream is(datastring, std::ios_base::binary);
1444 u16 count = readU16(is);
1446 for (u16 i = 0; i < count; ++i) {
1447 u16 peer_id = readU16(is);
1448 Player *player = m_env.getPlayer(peer_id);
1452 dout_client<<DTIME<<"Client: ignoring player item "
1453 << deSerializeString(is)
1454 << " for non-existing peer id " << peer_id
1457 } else if (player->isLocal()) {
1458 dout_client<<DTIME<<"Client: ignoring player item "
1459 << deSerializeString(is)
1460 << " for local player" << std::endl;
1463 InventoryList *inv = player->inventory.getList("main");
1464 std::string itemstring(deSerializeString(is));
1465 if (itemstring.empty()) {
1468 <<"Client: empty player item for peer "
1469 << peer_id << std::endl;
1471 std::istringstream iss(itemstring);
1472 delete inv->changeItem(0, InventoryItem::deSerialize(iss));
1473 dout_client<<DTIME<<"Client: player item for peer " << peer_id << ": ";
1474 player->getWieldItem()->serialize(dout_client);
1475 dout_client<<std::endl;
1482 dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command "
1483 <<command<<std::endl;
1487 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1489 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1490 m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1493 void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
1494 v3s16 nodepos_oversurface, u16 item)
1496 if(connectedAndInitialized() == false){
1497 dout_client<<DTIME<<"Client::groundAction() "
1498 "cancelled (not connected)"
1507 [3] v3s16 nodepos_undersurface
1508 [9] v3s16 nodepos_abovesurface
1513 2: stop digging (all parameters ignored)
1514 3: digging completed
1516 u8 datasize = 2 + 1 + 6 + 6 + 2;
1517 SharedBuffer<u8> data(datasize);
1518 writeU16(&data[0], TOSERVER_GROUND_ACTION);
1519 writeU8(&data[2], action);
1520 writeV3S16(&data[3], nodepos_undersurface);
1521 writeV3S16(&data[9], nodepos_oversurface);
1522 writeU16(&data[15], item);
1523 Send(0, data, true);
1526 void Client::clickActiveObject(u8 button, u16 id, u16 item_i)
1528 if(connectedAndInitialized() == false){
1529 dout_client<<DTIME<<"Client::clickActiveObject() "
1530 "cancelled (not connected)"
1535 Player *player = m_env.getLocalPlayer();
1539 ClientActiveObject *obj = m_env.getActiveObject(id);
1542 ToolItem *titem = NULL;
1543 std::string toolname = "";
1545 InventoryList *mlist = player->inventory.getList("main");
1548 InventoryItem *item = mlist->getItem(item_i);
1549 if(item && (std::string)item->getName() == "ToolItem")
1551 titem = (ToolItem*)item;
1552 toolname = titem->getToolName();
1556 v3f playerpos = player->getPosition();
1557 v3f objpos = obj->getPosition();
1558 v3f dir = (objpos - playerpos).normalize();
1560 bool disable_send = obj->directReportPunch(toolname, dir);
1570 [2] u8 button (0=left, 1=right)
1574 u8 datasize = 2 + 1 + 6 + 2 + 2;
1575 SharedBuffer<u8> data(datasize);
1576 writeU16(&data[0], TOSERVER_CLICK_ACTIVEOBJECT);
1577 writeU8(&data[2], button);
1578 writeU16(&data[3], id);
1579 writeU16(&data[5], item_i);
1580 Send(0, data, true);
1583 void Client::sendSignNodeText(v3s16 p, std::string text)
1591 std::ostringstream os(std::ios_base::binary);
1595 writeU16(buf, TOSERVER_SIGNNODETEXT);
1596 os.write((char*)buf, 2);
1600 os.write((char*)buf, 6);
1602 u16 textlen = text.size();
1603 // Write text length
1604 writeS16(buf, textlen);
1605 os.write((char*)buf, 2);
1608 os.write((char*)text.c_str(), textlen);
1611 std::string s = os.str();
1612 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1614 Send(0, data, true);
1617 void Client::sendInventoryAction(InventoryAction *a)
1619 std::ostringstream os(std::ios_base::binary);
1623 writeU16(buf, TOSERVER_INVENTORY_ACTION);
1624 os.write((char*)buf, 2);
1629 std::string s = os.str();
1630 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1632 Send(0, data, true);
1635 void Client::sendChatMessage(const std::wstring &message)
1637 std::ostringstream os(std::ios_base::binary);
1641 writeU16(buf, TOSERVER_CHAT_MESSAGE);
1642 os.write((char*)buf, 2);
1645 writeU16(buf, message.size());
1646 os.write((char*)buf, 2);
1649 for(u32 i=0; i<message.size(); i++)
1653 os.write((char*)buf, 2);
1657 std::string s = os.str();
1658 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1660 Send(0, data, true);
1663 void Client::sendChangePassword(const std::wstring oldpassword,
1664 const std::wstring newpassword)
1666 Player *player = m_env.getLocalPlayer();
1670 std::string playername = player->getName();
1671 std::string oldpwd = translatePassword(playername, oldpassword);
1672 std::string newpwd = translatePassword(playername, newpassword);
1674 std::ostringstream os(std::ios_base::binary);
1675 u8 buf[2+PASSWORD_SIZE*2];
1677 [0] u16 TOSERVER_PASSWORD
1678 [2] u8[28] old password
1679 [30] u8[28] new password
1682 writeU16(buf, TOSERVER_PASSWORD);
1683 for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1685 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1686 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1688 buf[2+PASSWORD_SIZE-1] = 0;
1689 buf[30+PASSWORD_SIZE-1] = 0;
1690 os.write((char*)buf, 2+PASSWORD_SIZE*2);
1693 std::string s = os.str();
1694 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1696 Send(0, data, true);
1700 void Client::sendDamage(u8 damage)
1702 DSTACK(__FUNCTION_NAME);
1703 std::ostringstream os(std::ios_base::binary);
1705 writeU16(os, TOSERVER_DAMAGE);
1706 writeU8(os, damage);
1709 std::string s = os.str();
1710 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1712 Send(0, data, true);
1715 void Client::sendPlayerPos()
1717 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1719 Player *myplayer = m_env.getLocalPlayer();
1720 if(myplayer == NULL)
1725 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1726 our_peer_id = m_con.GetPeerID();
1729 // Set peer id if not set already
1730 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1731 myplayer->peer_id = our_peer_id;
1732 // Check that an existing peer_id is the same as the connection's
1733 assert(myplayer->peer_id == our_peer_id);
1735 v3f pf = myplayer->getPosition();
1736 v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1737 v3f sf = myplayer->getSpeed();
1738 v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1739 s32 pitch = myplayer->getPitch() * 100;
1740 s32 yaw = myplayer->getYaw() * 100;
1745 [2] v3s32 position*100
1746 [2+12] v3s32 speed*100
1747 [2+12+12] s32 pitch*100
1748 [2+12+12+4] s32 yaw*100
1751 SharedBuffer<u8> data(2+12+12+4+4);
1752 writeU16(&data[0], TOSERVER_PLAYERPOS);
1753 writeV3S32(&data[2], position);
1754 writeV3S32(&data[2+12], speed);
1755 writeS32(&data[2+12+12], pitch);
1756 writeS32(&data[2+12+12+4], yaw);
1758 // Send as unreliable
1759 Send(0, data, false);
1762 void Client::sendPlayerItem(u16 item)
1764 Player *myplayer = m_env.getLocalPlayer();
1765 if(myplayer == NULL)
1768 u16 our_peer_id = m_con.GetPeerID();
1770 // Set peer id if not set already
1771 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1772 myplayer->peer_id = our_peer_id;
1773 // Check that an existing peer_id is the same as the connection's
1774 assert(myplayer->peer_id == our_peer_id);
1776 SharedBuffer<u8> data(2+2);
1777 writeU16(&data[0], TOSERVER_PLAYERITEM);
1778 writeU16(&data[2], item);
1781 Send(0, data, true);
1784 void Client::removeNode(v3s16 p)
1786 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1788 core::map<v3s16, MapBlock*> modified_blocks;
1792 //TimeTaker t("removeNodeAndUpdate", m_device);
1793 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1795 catch(InvalidPositionException &e)
1799 for(core::map<v3s16, MapBlock * >::Iterator
1800 i = modified_blocks.getIterator();
1801 i.atEnd() == false; i++)
1803 v3s16 p = i.getNode()->getKey();
1804 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1805 addUpdateMeshTaskWithEdge(p);
1809 void Client::addNode(v3s16 p, MapNode n)
1811 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1813 TimeTaker timer1("Client::addNode()");
1815 core::map<v3s16, MapBlock*> modified_blocks;
1819 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1820 std::string st = std::string("");
1821 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st);
1823 catch(InvalidPositionException &e)
1826 //TimeTaker timer2("Client::addNode(): updateMeshes");
1828 for(core::map<v3s16, MapBlock * >::Iterator
1829 i = modified_blocks.getIterator();
1830 i.atEnd() == false; i++)
1832 v3s16 p = i.getNode()->getKey();
1833 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1834 addUpdateMeshTaskWithEdge(p);
1838 void Client::updateCamera(v3f pos, v3f dir, f32 fov)
1840 m_env.getClientMap().updateCamera(pos, dir, fov);
1843 void Client::renderPostFx()
1845 m_env.getClientMap().renderPostFx();
1848 MapNode Client::getNode(v3s16 p)
1850 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1851 return m_env.getMap().getNode(p);
1854 NodeMetadata* Client::getNodeMetadata(v3s16 p)
1856 return m_env.getMap().getNodeMetadata(p);
1859 LocalPlayer* Client::getLocalPlayer()
1861 return m_env.getLocalPlayer();
1864 void Client::setPlayerControl(PlayerControl &control)
1866 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1867 LocalPlayer *player = m_env.getLocalPlayer();
1868 assert(player != NULL);
1869 player->control = control;
1872 void Client::selectPlayerItem(u16 item)
1874 LocalPlayer *player = m_env.getLocalPlayer();
1875 assert(player != NULL);
1877 player->wieldItem(item);
1879 sendPlayerItem(item);
1882 // Returns true if the inventory of the local player has been
1883 // updated from the server. If it is true, it is set to false.
1884 bool Client::getLocalInventoryUpdated()
1886 // m_inventory_updated is behind envlock
1887 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1888 bool updated = m_inventory_updated;
1889 m_inventory_updated = false;
1893 // Copies the inventory of the local player to parameter
1894 void Client::getLocalInventory(Inventory &dst)
1896 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1897 Player *player = m_env.getLocalPlayer();
1898 assert(player != NULL);
1899 dst = player->inventory;
1902 InventoryContext *Client::getInventoryContext()
1904 return &m_inventory_context;
1907 Inventory* Client::getInventory(InventoryContext *c, std::string id)
1909 if(id == "current_player")
1911 assert(c->current_player);
1912 return &(c->current_player->inventory);
1916 std::string id0 = fn.next(":");
1918 if(id0 == "nodemeta")
1921 p.X = stoi(fn.next(","));
1922 p.Y = stoi(fn.next(","));
1923 p.Z = stoi(fn.next(","));
1924 NodeMetadata* meta = getNodeMetadata(p);
1926 return meta->getInventory();
1927 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
1928 <<"no metadata found"<<std::endl;
1932 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
1935 void Client::inventoryAction(InventoryAction *a)
1937 sendInventoryAction(a);
1940 ClientActiveObject * Client::getSelectedActiveObject(
1942 v3f from_pos_f_on_map,
1943 core::line3d<f32> shootline_on_map
1946 core::array<DistanceSortedActiveObject> objects;
1948 m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
1950 //dstream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
1953 // After this, the closest object is the first in the array.
1956 for(u32 i=0; i<objects.size(); i++)
1958 ClientActiveObject *obj = objects[i].obj;
1960 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
1961 if(selection_box == NULL)
1964 v3f pos = obj->getPosition();
1966 core::aabbox3d<f32> offsetted_box(
1967 selection_box->MinEdge + pos,
1968 selection_box->MaxEdge + pos
1971 if(offsetted_box.intersectsWithLine(shootline_on_map))
1973 //dstream<<"Returning selected object"<<std::endl;
1978 //dstream<<"No object selected; returning NULL."<<std::endl;
1982 void Client::printDebugInfo(std::ostream &os)
1984 //JMutexAutoLock lock1(m_fetchblock_mutex);
1985 /*JMutexAutoLock lock2(m_incoming_queue_mutex);
1987 os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
1988 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
1989 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
1993 u32 Client::getDayNightRatio()
1995 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1996 return m_env.getDayNightRatio();
2001 Player *player = m_env.getLocalPlayer();
2002 assert(player != NULL);
2006 void Client::setTempMod(v3s16 p, NodeMod mod)
2008 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2009 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2011 core::map<v3s16, MapBlock*> affected_blocks;
2012 ((ClientMap&)m_env.getMap()).setTempMod(p, mod,
2015 for(core::map<v3s16, MapBlock*>::Iterator
2016 i = affected_blocks.getIterator();
2017 i.atEnd() == false; i++)
2019 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2023 void Client::clearTempMod(v3s16 p)
2025 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2026 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2028 core::map<v3s16, MapBlock*> affected_blocks;
2029 ((ClientMap&)m_env.getMap()).clearTempMod(p,
2032 for(core::map<v3s16, MapBlock*>::Iterator
2033 i = affected_blocks.getIterator();
2034 i.atEnd() == false; i++)
2036 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2040 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
2042 /*dstream<<"Client::addUpdateMeshTask(): "
2043 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2046 MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2051 Create a task to update the mesh of the block
2054 MeshMakeData *data = new MeshMakeData;
2057 //TimeTaker timer("data fill");
2059 // Debug: 1-6ms, avg=2ms
2060 data->fill(getDayNightRatio(), b);
2064 //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2066 // Add task to queue
2067 m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server);
2069 /*dstream<<"Mesh update input queue size is "
2070 <<m_mesh_update_thread.m_queue_in.size()
2074 // Temporary test: make mesh directly in here
2076 //TimeTaker timer("make mesh");
2078 scene::SMesh *mesh_new = NULL;
2079 mesh_new = makeMapBlockMesh(data);
2080 b->replaceMesh(mesh_new);
2086 Mark mesh as non-expired at this point so that it can already
2087 be marked as expired again if the data changes
2089 b->setMeshExpired(false);
2092 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
2096 dstream<<"Client::addUpdateMeshTaskWithEdge(): "
2097 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2102 v3s16 p = blockpos + v3s16(0,0,0);
2103 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2104 addUpdateMeshTask(p, ack_to_server);
2106 catch(InvalidPositionException &e){}
2109 v3s16 p = blockpos + v3s16(-1,0,0);
2110 addUpdateMeshTask(p);
2112 catch(InvalidPositionException &e){}
2114 v3s16 p = blockpos + v3s16(0,-1,0);
2115 addUpdateMeshTask(p);
2117 catch(InvalidPositionException &e){}
2119 v3s16 p = blockpos + v3s16(0,0,-1);
2120 addUpdateMeshTask(p);
2122 catch(InvalidPositionException &e){}
2125 ClientEvent Client::getClientEvent()
2127 if(m_client_event_queue.size() == 0)
2130 event.type = CE_NONE;
2133 return m_client_event_queue.pop_front();