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 ScopeProfiler sp(&g_profiler, "mesh make");
48 scene::SMesh *mesh_new = NULL;
49 mesh_new = makeMapBlockMesh(q->data);
54 r.ack_block_to_server = q->ack_block_to_server;
56 /*dstream<<"MeshUpdateThread: Processed "
57 <<"("<<q->p.X<<","<<q->p.Y<<","<<q->p.Z<<")"
60 m_queue_out.push_back(r);
65 END_DEBUG_EXCEPTION_HANDLER
71 IrrlichtDevice *device,
72 const char *playername,
74 MapDrawControl &control):
75 m_mesh_update_thread(),
77 new ClientMap(this, control,
78 device->getSceneManager()->getRootSceneNode(),
79 device->getSceneManager(), 666),
80 device->getSceneManager()
82 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
84 camera_position(0,0,0),
85 camera_direction(0,0,1),
86 m_server_ser_ver(SER_FMT_VER_INVALID),
87 m_inventory_updated(false),
91 m_access_denied(false)
93 m_packetcounter_timer = 0.0;
94 m_delete_unused_sectors_timer = 0.0;
95 m_connection_reinit_timer = 0.0;
96 m_avg_rtt_timer = 0.0;
97 m_playerpos_send_timer = 0.0;
98 m_ignore_damage_timer = 0.0;
100 //m_env_mutex.Init();
101 //m_con_mutex.Init();
103 m_mesh_update_thread.Start();
109 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
111 Player *player = new LocalPlayer();
113 player->updateName(playername);
115 m_env.addPlayer(player);
117 // Initialize player in the inventory context
118 m_inventory_context.current_player = player;
125 //JMutexAutoLock conlock(m_con_mutex); //bulk comment-out
129 m_mesh_update_thread.setRun(false);
130 while(m_mesh_update_thread.IsRunning())
134 void Client::connect(Address address)
136 DSTACK(__FUNCTION_NAME);
137 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
138 m_con.setTimeoutMs(0);
139 m_con.Connect(address);
142 bool Client::connectedAndInitialized()
144 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
146 if(m_con.Connected() == false)
149 if(m_server_ser_ver == SER_FMT_VER_INVALID)
155 void Client::step(float dtime)
157 DSTACK(__FUNCTION_NAME);
163 if(m_ignore_damage_timer > dtime)
164 m_ignore_damage_timer -= dtime;
166 m_ignore_damage_timer = 0.0;
168 //dstream<<"Client steps "<<dtime<<std::endl;
171 //TimeTaker timer("ReceiveAll()", m_device);
177 //TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device);
179 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
180 m_con.RunTimeouts(dtime);
187 float &counter = m_packetcounter_timer;
193 dout_client<<"Client packetcounter (20s):"<<std::endl;
194 m_packetcounter.print(dout_client);
195 m_packetcounter.clear();
201 Delete unused sectors
203 NOTE: This jams the game for a while because deleting sectors
207 float &counter = m_delete_unused_sectors_timer;
215 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
217 core::list<v3s16> deleted_blocks;
219 float delete_unused_sectors_timeout =
220 g_settings.getFloat("client_delete_unused_sectors_timeout");
222 // Delete sector blocks
223 /*u32 num = m_env.getMap().deleteUnusedSectors
224 (delete_unused_sectors_timeout,
225 true, &deleted_blocks);*/
227 // Delete whole sectors
228 u32 num = m_env.getMap().deleteUnusedSectors
229 (delete_unused_sectors_timeout,
230 false, &deleted_blocks);
234 /*dstream<<DTIME<<"Client: Deleted blocks of "<<num
235 <<" unused sectors"<<std::endl;*/
236 dstream<<DTIME<<"Client: Deleted "<<num
237 <<" unused sectors"<<std::endl;
243 // Env is locked so con can be locked.
244 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
246 core::list<v3s16>::Iterator i = deleted_blocks.begin();
247 core::list<v3s16> sendlist;
250 if(sendlist.size() == 255 || i == deleted_blocks.end())
252 if(sendlist.size() == 0)
261 u32 replysize = 2+1+6*sendlist.size();
262 SharedBuffer<u8> reply(replysize);
263 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
264 reply[2] = sendlist.size();
266 for(core::list<v3s16>::Iterator
267 j = sendlist.begin();
268 j != sendlist.end(); j++)
270 writeV3S16(&reply[2+1+6*k], *j);
273 m_con.Send(PEER_ID_SERVER, 1, reply, true);
275 if(i == deleted_blocks.end())
281 sendlist.push_back(*i);
288 bool connected = connectedAndInitialized();
290 if(connected == false)
292 float &counter = m_connection_reinit_timer;
298 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
300 Player *myplayer = m_env.getLocalPlayer();
301 assert(myplayer != NULL);
303 // Send TOSERVER_INIT
304 // [0] u16 TOSERVER_INIT
305 // [2] u8 SER_FMT_VER_HIGHEST
306 // [3] u8[20] player_name
307 // [23] u8[28] password
308 SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE);
309 writeU16(&data[0], TOSERVER_INIT);
310 writeU8(&data[2], SER_FMT_VER_HIGHEST);
312 memset((char*)&data[3], 0, PLAYERNAME_SIZE);
313 snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
315 /*dstream<<"Client: password hash is \""<<m_password<<"\""
318 memset((char*)&data[23], 0, PASSWORD_SIZE);
319 snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
321 // Send as unreliable
322 Send(0, data, false);
325 // Not connected, return
330 Do stuff if connected
338 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
340 // Control local player (0ms)
341 LocalPlayer *player = m_env.getLocalPlayer();
342 assert(player != NULL);
343 player->applyControl(dtime);
345 //TimeTaker envtimer("env step", m_device);
349 // Step active blocks
350 for(core::map<v3s16, bool>::Iterator
351 i = m_active_blocks.getIterator();
352 i.atEnd() == false; i++)
354 v3s16 p = i.getNode()->getKey();
356 MapBlock *block = NULL;
359 block = m_env.getMap().getBlockNoCreate(p);
360 block->stepObjects(dtime, false, m_env.getDayNightRatio());
362 catch(InvalidPositionException &e)
372 ClientEnvEvent event = m_env.getClientEvent();
373 if(event.type == CEE_NONE)
377 else if(event.type == CEE_PLAYER_DAMAGE)
379 if(m_ignore_damage_timer <= 0)
381 u8 damage = event.player_damage.amount;
384 // Add to ClientEvent queue
386 event.type = CE_PLAYER_DAMAGE;
387 event.player_damage.amount = damage;
388 m_client_event_queue.push_back(event);
398 float &counter = m_avg_rtt_timer;
403 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
404 // connectedAndInitialized() is true, peer exists.
405 con::Peer *peer = m_con.GetPeer(PEER_ID_SERVER);
406 dstream<<DTIME<<"Client: avg_rtt="<<peer->avg_rtt<<std::endl;
411 Send player position to server
414 float &counter = m_playerpos_send_timer;
424 Replace updated meshes
427 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
429 //TimeTaker timer("** Processing mesh update result queue");
432 /*dstream<<"Mesh update result queue size is "
433 <<m_mesh_update_thread.m_queue_out.size()
436 while(m_mesh_update_thread.m_queue_out.size() > 0)
438 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
439 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
442 block->replaceMesh(r.mesh);
444 if(r.ack_block_to_server)
446 /*dstream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
447 <<","<<r.p.Z<<")"<<std::endl;*/
458 u32 replysize = 2+1+6;
459 SharedBuffer<u8> reply(replysize);
460 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
462 writeV3S16(&reply[3], r.p);
464 m_con.Send(PEER_ID_SERVER, 1, reply, true);
470 // Virtual methods from con::PeerHandler
471 void Client::peerAdded(con::Peer *peer)
473 derr_client<<"Client::peerAdded(): peer->id="
474 <<peer->id<<std::endl;
476 void Client::deletingPeer(con::Peer *peer, bool timeout)
478 derr_client<<"Client::deletingPeer(): "
479 "Server Peer is getting deleted "
480 <<"(timeout="<<timeout<<")"<<std::endl;
483 void Client::ReceiveAll()
485 DSTACK(__FUNCTION_NAME);
491 catch(con::NoIncomingDataException &e)
495 catch(con::InvalidIncomingDataException &e)
497 dout_client<<DTIME<<"Client::ReceiveAll(): "
498 "InvalidIncomingDataException: what()="
499 <<e.what()<<std::endl;
504 void Client::Receive()
506 DSTACK(__FUNCTION_NAME);
507 u32 data_maxsize = 200000;
508 Buffer<u8> data(data_maxsize);
512 //TimeTaker t1("con mutex and receive", m_device);
513 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
514 datasize = m_con.Receive(sender_peer_id, *data, data_maxsize);
516 //TimeTaker t1("ProcessData", m_device);
517 ProcessData(*data, datasize, sender_peer_id);
521 sender_peer_id given to this shall be quaranteed to be a valid peer
523 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
525 DSTACK(__FUNCTION_NAME);
527 // Ignore packets that don't even fit a command
530 m_packetcounter.add(60000);
534 ToClientCommand command = (ToClientCommand)readU16(&data[0]);
536 //dstream<<"Client: received command="<<command<<std::endl;
537 m_packetcounter.add((u16)command);
540 If this check is removed, be sure to change the queue
541 system to know the ids
543 if(sender_peer_id != PEER_ID_SERVER)
545 dout_client<<DTIME<<"Client::ProcessData(): Discarding data not "
546 "coming from server: peer_id="<<sender_peer_id
553 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
554 // All data is coming from the server
555 // PeerNotFoundException is handled by caller.
556 peer = m_con.GetPeer(PEER_ID_SERVER);
559 u8 ser_version = m_server_ser_ver;
561 //dstream<<"Client received command="<<(int)command<<std::endl;
563 if(command == TOCLIENT_INIT)
568 u8 deployed = data[2];
570 dout_client<<DTIME<<"Client: TOCLIENT_INIT received with "
571 "deployed="<<((int)deployed&0xff)<<std::endl;
573 if(deployed < SER_FMT_VER_LOWEST
574 || deployed > SER_FMT_VER_HIGHEST)
576 derr_client<<DTIME<<"Client: TOCLIENT_INIT: Server sent "
577 <<"unsupported ser_fmt_ver"<<std::endl;
581 m_server_ser_ver = deployed;
583 // Get player position
584 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
585 if(datasize >= 2+1+6)
586 playerpos_s16 = readV3S16(&data[2+1]);
587 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
590 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
592 // Set player position
593 Player *player = m_env.getLocalPlayer();
594 assert(player != NULL);
595 player->setPosition(playerpos_f);
598 if(datasize >= 2+1+6+8)
601 m_map_seed = readU64(&data[2+1+6]);
602 dstream<<"Client: received map seed: "<<m_map_seed<<std::endl;
607 SharedBuffer<u8> reply(replysize);
608 writeU16(&reply[0], TOSERVER_INIT2);
610 m_con.Send(PEER_ID_SERVER, 1, reply, true);
615 if(command == TOCLIENT_ACCESS_DENIED)
617 // The server didn't like our password. Note, this needs
618 // to be processed even if the serialisation format has
619 // not been agreed yet, the same as TOCLIENT_INIT.
620 m_access_denied = true;
621 m_access_denied_reason = L"Unknown";
624 std::string datastring((char*)&data[2], datasize-2);
625 std::istringstream is(datastring, std::ios_base::binary);
626 m_access_denied_reason = deSerializeWideString(is);
631 if(ser_version == SER_FMT_VER_INVALID)
633 dout_client<<DTIME<<"WARNING: Client: Server serialization"
634 " format invalid or not initialized."
635 " Skipping incoming command="<<command<<std::endl;
639 // Just here to avoid putting the two if's together when
640 // making some copypasta
643 if(command == TOCLIENT_REMOVENODE)
648 p.X = readS16(&data[2]);
649 p.Y = readS16(&data[4]);
650 p.Z = readS16(&data[6]);
652 //TimeTaker t1("TOCLIENT_REMOVENODE");
654 // This will clear the cracking animation after digging
655 ((ClientMap&)m_env.getMap()).clearTempMod(p);
659 else if(command == TOCLIENT_ADDNODE)
661 if(datasize < 8 + MapNode::serializedLength(ser_version))
665 p.X = readS16(&data[2]);
666 p.Y = readS16(&data[4]);
667 p.Z = readS16(&data[6]);
669 //TimeTaker t1("TOCLIENT_ADDNODE");
672 n.deSerialize(&data[8], ser_version);
676 else if(command == TOCLIENT_BLOCKDATA)
678 // Ignore too small packet
683 p.X = readS16(&data[2]);
684 p.Y = readS16(&data[4]);
685 p.Z = readS16(&data[6]);
687 /*dout_client<<DTIME<<"Client: Thread: BLOCKDATA for ("
688 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
689 /*dstream<<DTIME<<"Client: Thread: BLOCKDATA for ("
690 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
692 std::string datastring((char*)&data[8], datasize-8);
693 std::istringstream istr(datastring, std::ios_base::binary);
699 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
702 sector = m_env.getMap().emergeSector(p2d);
704 v2s16 sp = sector->getPos();
707 dstream<<"ERROR: Got sector with getPos()="
708 <<"("<<sp.X<<","<<sp.Y<<"), tried to get"
709 <<"("<<p2d.X<<","<<p2d.Y<<")"<<std::endl;
713 //assert(sector->getPos() == p2d);
715 //TimeTaker timer("MapBlock deSerialize");
719 block = sector->getBlockNoCreate(p.Y);
721 Update an existing block
723 //dstream<<"Updating"<<std::endl;
724 block->deSerialize(istr, ser_version);
725 //block->setChangedFlag();
727 catch(InvalidPositionException &e)
732 //dstream<<"Creating new"<<std::endl;
733 block = new MapBlock(&m_env.getMap(), p);
734 block->deSerialize(istr, ser_version);
735 sector->insertBlock(block);
736 //block->setChangedFlag();
740 mod.type = NODEMOD_CHANGECONTENT;
741 mod.param = CONTENT_MESE;
742 block->setTempMod(v3s16(8,10,8), mod);
743 block->setTempMod(v3s16(8,9,8), mod);
744 block->setTempMod(v3s16(8,8,8), mod);
745 block->setTempMod(v3s16(8,7,8), mod);
746 block->setTempMod(v3s16(8,6,8), mod);*/
750 Well, this is a dumb way to do it, they should just
751 be drawn as separate objects. But the looks of them
752 can be tested this way.
757 mod.type = NODEMOD_CHANGECONTENT;
758 mod.param = CONTENT_CLOUD;
761 for(p2.X=3; p2.X<=13; p2.X++)
762 for(p2.Z=3; p2.Z<=13; p2.Z++)
764 block->setTempMod(p2, mod);
782 u32 replysize = 2+1+6;
783 SharedBuffer<u8> reply(replysize);
784 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
786 writeV3S16(&reply[3], p);
788 m_con.Send(PEER_ID_SERVER, 1, reply, true);
792 Update Mesh of this block and blocks at x-, y- and z-.
793 Environment should not be locked as it interlocks with the
794 main thread, from which is will want to retrieve textures.
797 //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
799 addUpdateMeshTaskWithEdge(p, true);
801 else if(command == TOCLIENT_PLAYERPOS)
803 dstream<<"WARNING: Received deprecated TOCLIENT_PLAYERPOS"
807 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
808 our_peer_id = m_con.GetPeerID();
810 // Cancel if we don't have a peer id
811 if(our_peer_id == PEER_ID_INEXISTENT){
812 dout_client<<DTIME<<"TOCLIENT_PLAYERPOS cancelled: "
819 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
821 u32 player_size = 2+12+12+4+4;
823 u32 player_count = (datasize-2) / player_size;
825 for(u32 i=0; i<player_count; i++)
827 u16 peer_id = readU16(&data[start]);
829 Player *player = m_env.getPlayer(peer_id);
831 // Skip if player doesn't exist
834 start += player_size;
838 // Skip if player is local player
839 if(player->isLocal())
841 start += player_size;
845 v3s32 ps = readV3S32(&data[start+2]);
846 v3s32 ss = readV3S32(&data[start+2+12]);
847 s32 pitch_i = readS32(&data[start+2+12+12]);
848 s32 yaw_i = readS32(&data[start+2+12+12+4]);
849 /*dstream<<"Client: got "
850 <<"pitch_i="<<pitch_i
851 <<" yaw_i="<<yaw_i<<std::endl;*/
852 f32 pitch = (f32)pitch_i / 100.0;
853 f32 yaw = (f32)yaw_i / 100.0;
854 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
855 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
856 player->setPosition(position);
857 player->setSpeed(speed);
858 player->setPitch(pitch);
861 /*dstream<<"Client: player "<<peer_id
863 <<" yaw="<<yaw<<std::endl;*/
865 start += player_size;
869 else if(command == TOCLIENT_PLAYERINFO)
873 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
874 our_peer_id = m_con.GetPeerID();
876 // Cancel if we don't have a peer id
877 if(our_peer_id == PEER_ID_INEXISTENT){
878 dout_client<<DTIME<<"TOCLIENT_PLAYERINFO cancelled: "
884 //dstream<<DTIME<<"Client: Server reports players:"<<std::endl;
887 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
889 u32 item_size = 2+PLAYERNAME_SIZE;
890 u32 player_count = (datasize-2) / item_size;
893 core::list<u16> players_alive;
894 for(u32 i=0; i<player_count; i++)
896 // Make sure the name ends in '\0'
897 data[start+2+20-1] = 0;
899 u16 peer_id = readU16(&data[start]);
901 players_alive.push_back(peer_id);
903 /*dstream<<DTIME<<"peer_id="<<peer_id
904 <<" name="<<((char*)&data[start+2])<<std::endl;*/
906 // Don't update the info of the local player
907 if(peer_id == our_peer_id)
913 Player *player = m_env.getPlayer(peer_id);
915 // Create a player if it doesn't exist
918 player = new RemotePlayer(
919 m_device->getSceneManager()->getRootSceneNode(),
922 player->peer_id = peer_id;
923 m_env.addPlayer(player);
924 dout_client<<DTIME<<"Client: Adding new player "
925 <<peer_id<<std::endl;
928 player->updateName((char*)&data[start+2]);
934 Remove those players from the environment that
935 weren't listed by the server.
937 //dstream<<DTIME<<"Removing dead players"<<std::endl;
938 core::list<Player*> players = m_env.getPlayers();
939 core::list<Player*>::Iterator ip;
940 for(ip=players.begin(); ip!=players.end(); ip++)
942 // Ingore local player
946 // Warn about a special case
947 if((*ip)->peer_id == 0)
949 dstream<<DTIME<<"WARNING: Client: Removing "
950 "dead player with id=0"<<std::endl;
953 bool is_alive = false;
954 core::list<u16>::Iterator i;
955 for(i=players_alive.begin(); i!=players_alive.end(); i++)
957 if((*ip)->peer_id == *i)
963 /*dstream<<DTIME<<"peer_id="<<((*ip)->peer_id)
964 <<" is_alive="<<is_alive<<std::endl;*/
967 dstream<<DTIME<<"Removing dead player "<<(*ip)->peer_id
969 m_env.removePlayer((*ip)->peer_id);
973 else if(command == TOCLIENT_SECTORMETA)
978 [3...] v2s16 pos + sector metadata
983 //dstream<<"Client received TOCLIENT_SECTORMETA"<<std::endl;
986 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
988 std::string datastring((char*)&data[2], datasize-2);
989 std::istringstream is(datastring, std::ios_base::binary);
993 is.read((char*)buf, 1);
994 u16 sector_count = readU8(buf);
996 //dstream<<"sector_count="<<sector_count<<std::endl;
998 for(u16 i=0; i<sector_count; i++)
1001 is.read((char*)buf, 4);
1002 v2s16 pos = readV2S16(buf);
1003 /*dstream<<"Client: deserializing sector at "
1004 <<"("<<pos.X<<","<<pos.Y<<")"<<std::endl;*/
1006 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
1007 ((ClientMap&)m_env.getMap()).deSerializeSector(pos, is);
1011 else if(command == TOCLIENT_INVENTORY)
1016 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
1019 //TimeTaker t2("mutex locking", m_device);
1020 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1023 //TimeTaker t3("istringstream init", m_device);
1024 std::string datastring((char*)&data[2], datasize-2);
1025 std::istringstream is(datastring, std::ios_base::binary);
1028 //m_env.printPlayers(dstream);
1030 //TimeTaker t4("player get", m_device);
1031 Player *player = m_env.getLocalPlayer();
1032 assert(player != NULL);
1035 //TimeTaker t1("inventory.deSerialize()", m_device);
1036 player->inventory.deSerialize(is);
1039 m_inventory_updated = true;
1041 //dstream<<"Client got player inventory:"<<std::endl;
1042 //player->inventory.print(dstream);
1046 else if(command == TOCLIENT_OBJECTDATA)
1049 // Strip command word and create a stringstream
1050 std::string datastring((char*)&data[2], datasize-2);
1051 std::istringstream is(datastring, std::ios_base::binary);
1055 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1063 is.read((char*)buf, 2);
1064 u16 playercount = readU16(buf);
1066 for(u16 i=0; i<playercount; i++)
1068 is.read((char*)buf, 2);
1069 u16 peer_id = readU16(buf);
1070 is.read((char*)buf, 12);
1071 v3s32 p_i = readV3S32(buf);
1072 is.read((char*)buf, 12);
1073 v3s32 s_i = readV3S32(buf);
1074 is.read((char*)buf, 4);
1075 s32 pitch_i = readS32(buf);
1076 is.read((char*)buf, 4);
1077 s32 yaw_i = readS32(buf);
1079 Player *player = m_env.getPlayer(peer_id);
1081 // Skip if player doesn't exist
1087 // Skip if player is local player
1088 if(player->isLocal())
1093 f32 pitch = (f32)pitch_i / 100.0;
1094 f32 yaw = (f32)yaw_i / 100.0;
1095 v3f position((f32)p_i.X/100., (f32)p_i.Y/100., (f32)p_i.Z/100.);
1096 v3f speed((f32)s_i.X/100., (f32)s_i.Y/100., (f32)s_i.Z/100.);
1098 player->setPosition(position);
1099 player->setSpeed(speed);
1100 player->setPitch(pitch);
1101 player->setYaw(yaw);
1108 // Read active block count
1109 is.read((char*)buf, 2);
1110 u16 blockcount = readU16(buf);
1112 // Initialize delete queue with all active blocks
1113 core::map<v3s16, bool> abs_to_delete;
1114 for(core::map<v3s16, bool>::Iterator
1115 i = m_active_blocks.getIterator();
1116 i.atEnd() == false; i++)
1118 v3s16 p = i.getNode()->getKey();
1119 /*dstream<<"adding "
1120 <<"("<<p.x<<","<<p.y<<","<<p.z<<") "
1121 <<" to abs_to_delete"
1123 abs_to_delete.insert(p, true);
1126 /*dstream<<"Initial delete queue size: "<<abs_to_delete.size()
1129 for(u16 i=0; i<blockcount; i++)
1132 is.read((char*)buf, 6);
1133 v3s16 p = readV3S16(buf);
1134 // Get block from somewhere
1135 MapBlock *block = NULL;
1137 block = m_env.getMap().getBlockNoCreate(p);
1139 catch(InvalidPositionException &e)
1141 //TODO: Create a dummy block?
1145 dstream<<"WARNING: "
1146 <<"Could not get block at blockpos "
1147 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
1148 <<"in TOCLIENT_OBJECTDATA. Ignoring "
1149 <<"following block object data."
1154 /*dstream<<"Client updating objects for block "
1155 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1158 // Insert to active block list
1159 m_active_blocks.insert(p, true);
1161 // Remove from deletion queue
1162 if(abs_to_delete.find(p) != NULL)
1163 abs_to_delete.remove(p);
1166 Update objects of block
1168 NOTE: Be sure this is done in the main thread.
1170 block->updateObjects(is, m_server_ser_ver,
1171 m_device->getSceneManager(), m_env.getDayNightRatio());
1174 /*dstream<<"Final delete queue size: "<<abs_to_delete.size()
1177 // Delete objects of blocks in delete queue
1178 for(core::map<v3s16, bool>::Iterator
1179 i = abs_to_delete.getIterator();
1180 i.atEnd() == false; i++)
1182 v3s16 p = i.getNode()->getKey();
1185 MapBlock *block = m_env.getMap().getBlockNoCreate(p);
1188 block->clearObjects();
1189 // Remove from active blocks list
1190 m_active_blocks.remove(p);
1192 catch(InvalidPositionException &e)
1194 dstream<<"WARNAING: Client: "
1195 <<"Couldn't clear objects of active->inactive"
1197 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1198 <<" because block was not found"
1206 else if(command == TOCLIENT_TIME_OF_DAY)
1211 u16 time_of_day = readU16(&data[2]);
1212 time_of_day = time_of_day % 24000;
1213 //dstream<<"Client: time_of_day="<<time_of_day<<std::endl;
1221 m_env.setTimeOfDay(time_of_day);
1223 u32 dr = m_env.getDayNightRatio();
1225 dstream<<"Client: time_of_day="<<time_of_day
1231 else if(command == TOCLIENT_CHAT_MESSAGE)
1239 std::string datastring((char*)&data[2], datasize-2);
1240 std::istringstream is(datastring, std::ios_base::binary);
1243 is.read((char*)buf, 2);
1244 u16 len = readU16(buf);
1246 std::wstring message;
1247 for(u16 i=0; i<len; i++)
1249 is.read((char*)buf, 2);
1250 message += (wchar_t)readU16(buf);
1253 /*dstream<<"Client received chat message: "
1254 <<wide_to_narrow(message)<<std::endl;*/
1256 m_chat_queue.push_back(message);
1258 else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1260 //if(g_settings.getBool("enable_experimental"))
1264 u16 count of removed objects
1265 for all removed objects {
1268 u16 count of added objects
1269 for all added objects {
1272 u16 initialization data length
1273 string initialization data
1278 // Get all data except the command number
1279 std::string datastring((char*)&data[2], datasize-2);
1280 // Throw them in an istringstream
1281 std::istringstream is(datastring, std::ios_base::binary);
1285 // Read removed objects
1287 u16 removed_count = readU16((u8*)buf);
1288 for(u16 i=0; i<removed_count; i++)
1291 u16 id = readU16((u8*)buf);
1294 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1295 m_env.removeActiveObject(id);
1299 // Read added objects
1301 u16 added_count = readU16((u8*)buf);
1302 for(u16 i=0; i<added_count; i++)
1305 u16 id = readU16((u8*)buf);
1307 u8 type = readU8((u8*)buf);
1308 std::string data = deSerializeLongString(is);
1311 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1312 m_env.addActiveObject(id, type, data);
1317 else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1319 //if(g_settings.getBool("enable_experimental"))
1331 // Get all data except the command number
1332 std::string datastring((char*)&data[2], datasize-2);
1333 // Throw them in an istringstream
1334 std::istringstream is(datastring, std::ios_base::binary);
1336 while(is.eof() == false)
1340 u16 id = readU16((u8*)buf);
1344 u16 message_size = readU16((u8*)buf);
1345 std::string message;
1346 message.reserve(message_size);
1347 for(u16 i=0; i<message_size; i++)
1350 message.append(buf, 1);
1352 // Pass on to the environment
1354 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1355 m_env.processActiveObjectMessage(id, message);
1360 else if(command == TOCLIENT_HP)
1362 std::string datastring((char*)&data[2], datasize-2);
1363 std::istringstream is(datastring, std::ios_base::binary);
1364 Player *player = m_env.getLocalPlayer();
1365 assert(player != NULL);
1369 else if(command == TOCLIENT_MOVE_PLAYER)
1371 std::string datastring((char*)&data[2], datasize-2);
1372 std::istringstream is(datastring, std::ios_base::binary);
1373 Player *player = m_env.getLocalPlayer();
1374 assert(player != NULL);
1375 v3f pos = readV3F1000(is);
1376 f32 pitch = readF1000(is);
1377 f32 yaw = readF1000(is);
1378 player->setPosition(pos);
1379 /*player->setPitch(pitch);
1380 player->setYaw(yaw);*/
1382 dstream<<"Client got TOCLIENT_MOVE_PLAYER"
1383 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1389 Add to ClientEvent queue.
1390 This has to be sent to the main program because otherwise
1391 it would just force the pitch and yaw values to whatever
1392 the camera points to.
1395 event.type = CE_PLAYER_FORCE_MOVE;
1396 event.player_force_move.pitch = pitch;
1397 event.player_force_move.yaw = yaw;
1398 m_client_event_queue.push_back(event);
1400 // Ignore damage for a few seconds, so that the player doesn't
1401 // get damage from falling on ground
1402 m_ignore_damage_timer = 3.0;
1406 dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command "
1407 <<command<<std::endl;
1411 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1413 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1414 m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1417 void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
1418 v3s16 nodepos_oversurface, u16 item)
1420 if(connectedAndInitialized() == false){
1421 dout_client<<DTIME<<"Client::groundAction() "
1422 "cancelled (not connected)"
1431 [3] v3s16 nodepos_undersurface
1432 [9] v3s16 nodepos_abovesurface
1437 2: stop digging (all parameters ignored)
1438 3: digging completed
1440 u8 datasize = 2 + 1 + 6 + 6 + 2;
1441 SharedBuffer<u8> data(datasize);
1442 writeU16(&data[0], TOSERVER_GROUND_ACTION);
1443 writeU8(&data[2], action);
1444 writeV3S16(&data[3], nodepos_undersurface);
1445 writeV3S16(&data[9], nodepos_oversurface);
1446 writeU16(&data[15], item);
1447 Send(0, data, true);
1450 void Client::clickObject(u8 button, v3s16 blockpos, s16 id, u16 item)
1452 if(connectedAndInitialized() == false){
1453 dout_client<<DTIME<<"Client::clickObject() "
1454 "cancelled (not connected)"
1460 [0] u16 command=TOSERVER_CLICK_OBJECT
1461 [2] u8 button (0=left, 1=right)
1466 u8 datasize = 2 + 1 + 6 + 2 + 2;
1467 SharedBuffer<u8> data(datasize);
1468 writeU16(&data[0], TOSERVER_CLICK_OBJECT);
1469 writeU8(&data[2], button);
1470 writeV3S16(&data[3], blockpos);
1471 writeS16(&data[9], id);
1472 writeU16(&data[11], item);
1473 Send(0, data, true);
1476 void Client::clickActiveObject(u8 button, u16 id, u16 item)
1478 if(connectedAndInitialized() == false){
1479 dout_client<<DTIME<<"Client::clickActiveObject() "
1480 "cancelled (not connected)"
1488 [2] u8 button (0=left, 1=right)
1492 u8 datasize = 2 + 1 + 6 + 2 + 2;
1493 SharedBuffer<u8> data(datasize);
1494 writeU16(&data[0], TOSERVER_CLICK_ACTIVEOBJECT);
1495 writeU8(&data[2], button);
1496 writeU16(&data[3], id);
1497 writeU16(&data[5], item);
1498 Send(0, data, true);
1501 void Client::sendSignText(v3s16 blockpos, s16 id, std::string text)
1510 std::ostringstream os(std::ios_base::binary);
1514 writeU16(buf, TOSERVER_SIGNTEXT);
1515 os.write((char*)buf, 2);
1518 writeV3S16(buf, blockpos);
1519 os.write((char*)buf, 6);
1523 os.write((char*)buf, 2);
1525 u16 textlen = text.size();
1526 // Write text length
1527 writeS16(buf, textlen);
1528 os.write((char*)buf, 2);
1531 os.write((char*)text.c_str(), textlen);
1534 std::string s = os.str();
1535 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1537 Send(0, data, true);
1540 void Client::sendSignNodeText(v3s16 p, std::string text)
1548 std::ostringstream os(std::ios_base::binary);
1552 writeU16(buf, TOSERVER_SIGNNODETEXT);
1553 os.write((char*)buf, 2);
1557 os.write((char*)buf, 6);
1559 u16 textlen = text.size();
1560 // Write text length
1561 writeS16(buf, textlen);
1562 os.write((char*)buf, 2);
1565 os.write((char*)text.c_str(), textlen);
1568 std::string s = os.str();
1569 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1571 Send(0, data, true);
1574 void Client::sendInventoryAction(InventoryAction *a)
1576 std::ostringstream os(std::ios_base::binary);
1580 writeU16(buf, TOSERVER_INVENTORY_ACTION);
1581 os.write((char*)buf, 2);
1586 std::string s = os.str();
1587 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1589 Send(0, data, true);
1592 void Client::sendChatMessage(const std::wstring &message)
1594 std::ostringstream os(std::ios_base::binary);
1598 writeU16(buf, TOSERVER_CHAT_MESSAGE);
1599 os.write((char*)buf, 2);
1602 writeU16(buf, message.size());
1603 os.write((char*)buf, 2);
1606 for(u32 i=0; i<message.size(); i++)
1610 os.write((char*)buf, 2);
1614 std::string s = os.str();
1615 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1617 Send(0, data, true);
1620 void Client::sendChangePassword(const std::wstring oldpassword,
1621 const std::wstring newpassword)
1623 Player *player = m_env.getLocalPlayer();
1627 std::string playername = player->getName();
1628 std::string oldpwd = translatePassword(playername, oldpassword);
1629 std::string newpwd = translatePassword(playername, newpassword);
1631 std::ostringstream os(std::ios_base::binary);
1632 u8 buf[2+PASSWORD_SIZE*2];
1634 [0] u16 TOSERVER_PASSWORD
1635 [2] u8[28] old password
1636 [30] u8[28] new password
1639 writeU16(buf, TOSERVER_PASSWORD);
1640 for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1642 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1643 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1645 buf[2+PASSWORD_SIZE-1] = 0;
1646 buf[30+PASSWORD_SIZE-1] = 0;
1647 os.write((char*)buf, 2+PASSWORD_SIZE*2);
1650 std::string s = os.str();
1651 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1653 Send(0, data, true);
1657 void Client::sendDamage(u8 damage)
1659 DSTACK(__FUNCTION_NAME);
1660 std::ostringstream os(std::ios_base::binary);
1662 writeU16(os, TOSERVER_DAMAGE);
1663 writeU8(os, damage);
1666 std::string s = os.str();
1667 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1669 Send(0, data, true);
1672 void Client::sendPlayerPos()
1674 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1676 Player *myplayer = m_env.getLocalPlayer();
1677 if(myplayer == NULL)
1682 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1683 our_peer_id = m_con.GetPeerID();
1686 // Set peer id if not set already
1687 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1688 myplayer->peer_id = our_peer_id;
1689 // Check that an existing peer_id is the same as the connection's
1690 assert(myplayer->peer_id == our_peer_id);
1692 v3f pf = myplayer->getPosition();
1693 v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1694 v3f sf = myplayer->getSpeed();
1695 v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1696 s32 pitch = myplayer->getPitch() * 100;
1697 s32 yaw = myplayer->getYaw() * 100;
1702 [2] v3s32 position*100
1703 [2+12] v3s32 speed*100
1704 [2+12+12] s32 pitch*100
1705 [2+12+12+4] s32 yaw*100
1708 SharedBuffer<u8> data(2+12+12+4+4);
1709 writeU16(&data[0], TOSERVER_PLAYERPOS);
1710 writeV3S32(&data[2], position);
1711 writeV3S32(&data[2+12], speed);
1712 writeS32(&data[2+12+12], pitch);
1713 writeS32(&data[2+12+12+4], yaw);
1715 // Send as unreliable
1716 Send(0, data, false);
1719 void Client::removeNode(v3s16 p)
1721 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1723 core::map<v3s16, MapBlock*> modified_blocks;
1727 //TimeTaker t("removeNodeAndUpdate", m_device);
1728 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1730 catch(InvalidPositionException &e)
1734 for(core::map<v3s16, MapBlock * >::Iterator
1735 i = modified_blocks.getIterator();
1736 i.atEnd() == false; i++)
1738 v3s16 p = i.getNode()->getKey();
1739 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1740 addUpdateMeshTaskWithEdge(p);
1744 void Client::addNode(v3s16 p, MapNode n)
1746 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1748 TimeTaker timer1("Client::addNode()");
1750 core::map<v3s16, MapBlock*> modified_blocks;
1754 TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1755 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
1757 catch(InvalidPositionException &e)
1760 //TimeTaker timer2("Client::addNode(): updateMeshes");
1762 for(core::map<v3s16, MapBlock * >::Iterator
1763 i = modified_blocks.getIterator();
1764 i.atEnd() == false; i++)
1766 v3s16 p = i.getNode()->getKey();
1767 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1768 addUpdateMeshTaskWithEdge(p);
1772 void Client::updateCamera(v3f pos, v3f dir)
1774 m_env.getClientMap().updateCamera(pos, dir);
1775 camera_position = pos;
1776 camera_direction = dir;
1779 MapNode Client::getNode(v3s16 p)
1781 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1782 return m_env.getMap().getNode(p);
1785 NodeMetadata* Client::getNodeMetadata(v3s16 p)
1787 return m_env.getMap().getNodeMetadata(p);
1790 v3f Client::getPlayerPosition()
1792 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1793 LocalPlayer *player = m_env.getLocalPlayer();
1794 assert(player != NULL);
1795 return player->getPosition();
1798 void Client::setPlayerControl(PlayerControl &control)
1800 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1801 LocalPlayer *player = m_env.getLocalPlayer();
1802 assert(player != NULL);
1803 player->control = control;
1806 // Returns true if the inventory of the local player has been
1807 // updated from the server. If it is true, it is set to false.
1808 bool Client::getLocalInventoryUpdated()
1810 // m_inventory_updated is behind envlock
1811 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1812 bool updated = m_inventory_updated;
1813 m_inventory_updated = false;
1817 // Copies the inventory of the local player to parameter
1818 void Client::getLocalInventory(Inventory &dst)
1820 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1821 Player *player = m_env.getLocalPlayer();
1822 assert(player != NULL);
1823 dst = player->inventory;
1826 InventoryContext *Client::getInventoryContext()
1828 return &m_inventory_context;
1831 Inventory* Client::getInventory(InventoryContext *c, std::string id)
1833 if(id == "current_player")
1835 assert(c->current_player);
1836 return &(c->current_player->inventory);
1840 std::string id0 = fn.next(":");
1842 if(id0 == "nodemeta")
1845 p.X = stoi(fn.next(","));
1846 p.Y = stoi(fn.next(","));
1847 p.Z = stoi(fn.next(","));
1848 NodeMetadata* meta = getNodeMetadata(p);
1850 return meta->getInventory();
1851 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
1852 <<"no metadata found"<<std::endl;
1856 dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
1859 void Client::inventoryAction(InventoryAction *a)
1861 sendInventoryAction(a);
1864 MapBlockObject * Client::getSelectedObject(
1866 v3f from_pos_f_on_map,
1867 core::line3d<f32> shootline_on_map
1870 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1872 core::array<DistanceSortedObject> objects;
1874 for(core::map<v3s16, bool>::Iterator
1875 i = m_active_blocks.getIterator();
1876 i.atEnd() == false; i++)
1878 v3s16 p = i.getNode()->getKey();
1880 MapBlock *block = NULL;
1883 block = m_env.getMap().getBlockNoCreate(p);
1885 catch(InvalidPositionException &e)
1890 // Calculate from_pos relative to block
1891 v3s16 block_pos_i_on_map = block->getPosRelative();
1892 v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
1893 v3f from_pos_f_on_block = from_pos_f_on_map - block_pos_f_on_map;
1895 block->getObjects(from_pos_f_on_block, max_d, objects);
1896 //block->getPseudoObjects(from_pos_f_on_block, max_d, objects);
1899 //dstream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
1902 // After this, the closest object is the first in the array.
1905 for(u32 i=0; i<objects.size(); i++)
1907 MapBlockObject *obj = objects[i].obj;
1908 MapBlock *block = obj->getBlock();
1910 // Calculate shootline relative to block
1911 v3s16 block_pos_i_on_map = block->getPosRelative();
1912 v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map, BS);
1913 core::line3d<f32> shootline_on_block(
1914 shootline_on_map.start - block_pos_f_on_map,
1915 shootline_on_map.end - block_pos_f_on_map
1918 if(obj->isSelected(shootline_on_block))
1920 //dstream<<"Returning selected object"<<std::endl;
1925 //dstream<<"No object selected; returning NULL."<<std::endl;
1929 ClientActiveObject * Client::getSelectedActiveObject(
1931 v3f from_pos_f_on_map,
1932 core::line3d<f32> shootline_on_map
1935 core::array<DistanceSortedActiveObject> objects;
1937 m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
1939 //dstream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
1942 // After this, the closest object is the first in the array.
1945 for(u32 i=0; i<objects.size(); i++)
1947 ClientActiveObject *obj = objects[i].obj;
1949 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
1950 if(selection_box == NULL)
1953 v3f pos = obj->getPosition();
1955 core::aabbox3d<f32> offsetted_box(
1956 selection_box->MinEdge + pos,
1957 selection_box->MaxEdge + pos
1960 if(offsetted_box.intersectsWithLine(shootline_on_map))
1962 //dstream<<"Returning selected object"<<std::endl;
1967 //dstream<<"No object selected; returning NULL."<<std::endl;
1971 void Client::printDebugInfo(std::ostream &os)
1973 //JMutexAutoLock lock1(m_fetchblock_mutex);
1974 /*JMutexAutoLock lock2(m_incoming_queue_mutex);
1976 os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
1977 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
1978 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
1982 /*s32 Client::getDayNightIndex()
1984 assert(m_daynight_i >= 0 && m_daynight_i < DAYNIGHT_CACHE_COUNT);
1985 return m_daynight_i;
1988 u32 Client::getDayNightRatio()
1990 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1991 return m_env.getDayNightRatio();
1996 Player *player = m_env.getLocalPlayer();
1997 assert(player != NULL);
2001 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
2003 /*dstream<<"Client::addUpdateMeshTask(): "
2004 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2007 MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2012 Create a task to update the mesh of the block
2015 MeshMakeData *data = new MeshMakeData;
2018 //TimeTaker timer("data fill");
2020 data->fill(getDayNightRatio(), b);
2024 //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2026 // Add task to queue
2027 m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server);
2029 /*dstream<<"Mesh update input queue size is "
2030 <<m_mesh_update_thread.m_queue_in.size()
2034 // Temporary test: make mesh directly in here
2036 //TimeTaker timer("make mesh");
2038 scene::SMesh *mesh_new = NULL;
2039 mesh_new = makeMapBlockMesh(data);
2040 b->replaceMesh(mesh_new);
2045 b->setMeshExpired(false);
2048 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
2052 dstream<<"Client::addUpdateMeshTaskWithEdge(): "
2053 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2058 v3s16 p = blockpos + v3s16(0,0,0);
2059 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2060 addUpdateMeshTask(p, ack_to_server);
2062 catch(InvalidPositionException &e){}
2065 v3s16 p = blockpos + v3s16(-1,0,0);
2066 addUpdateMeshTask(p);
2068 catch(InvalidPositionException &e){}
2070 v3s16 p = blockpos + v3s16(0,-1,0);
2071 addUpdateMeshTask(p);
2073 catch(InvalidPositionException &e){}
2075 v3s16 p = blockpos + v3s16(0,0,-1);
2076 addUpdateMeshTask(p);
2078 catch(InvalidPositionException &e){}
2081 ClientEvent Client::getClientEvent()
2083 if(m_client_event_queue.size() == 0)
2086 event.type = CE_NONE;
2089 return m_client_event_queue.pop_front();