starting to separate "material" to "content" and "tile"
[oweals/minetest.git] / src / server.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
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.
9
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.
14
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.
18 */
19
20 /*
21 (c) 2010 Perttu Ahola <celeron55@gmail.com>
22 */
23
24 #include "server.h"
25 #include "utility.h"
26 #include <iostream>
27 #include "clientserver.h"
28 #include "map.h"
29 #include "jmutexautolock.h"
30 #include "main.h"
31 #include "constants.h"
32 #include "voxel.h"
33
34 void * ServerThread::Thread()
35 {
36         ThreadStarted();
37
38         DSTACK(__FUNCTION_NAME);
39
40         while(getRun())
41         {
42                 try{
43                         m_server->AsyncRunStep();
44                 
45                         //dout_server<<"Running m_server->Receive()"<<std::endl;
46                         m_server->Receive();
47                 }
48                 catch(con::NoIncomingDataException &e)
49                 {
50                 }
51 #if CATCH_UNHANDLED_EXCEPTIONS
52                 /*
53                         This is what has to be done in threads to get suitable debug info
54                 */
55                 catch(std::exception &e)
56                 {
57                         dstream<<std::endl<<DTIME<<"An unhandled exception occurred: "
58                                         <<e.what()<<std::endl;
59                         assert(0);
60                 }
61 #endif
62         }
63         
64
65         return NULL;
66 }
67
68 void * EmergeThread::Thread()
69 {
70         ThreadStarted();
71
72         DSTACK(__FUNCTION_NAME);
73
74         bool debug=false;
75 #if CATCH_UNHANDLED_EXCEPTIONS
76         try
77         {
78 #endif
79         
80         /*
81                 Get block info from queue, emerge them and send them
82                 to clients.
83
84                 After queue is empty, exit.
85         */
86         while(getRun())
87         {
88                 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
89                 if(qptr == NULL)
90                         break;
91                 
92                 SharedPtr<QueuedBlockEmerge> q(qptr);
93
94                 v3s16 &p = q->pos;
95                 
96                 //derr_server<<"EmergeThread::Thread(): running"<<std::endl;
97                 
98                 /*
99                         Try to emerge it from somewhere.
100
101                         If it is only wanted as optional, only loading from disk
102                         will be allowed.
103                 */
104                 
105                 /*
106                         Check if any peer wants it as non-optional. In that case it
107                         will be generated.
108
109                         Also decrement the emerge queue count in clients.
110                 */
111
112                 bool optional = true;
113
114                 {
115                         core::map<u16, u8>::Iterator i;
116                         for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
117                         {
118                                 //u16 peer_id = i.getNode()->getKey();
119
120                                 // Check flags
121                                 u8 flags = i.getNode()->getValue();
122                                 if((flags & TOSERVER_GETBLOCK_FLAG_OPTIONAL) == false)
123                                         optional = false;
124                                 
125                         }
126                 }
127
128                 /*dstream<<"EmergeThread: p="
129                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
130                                 <<"optional="<<optional<<std::endl;*/
131                 
132                 ServerMap &map = ((ServerMap&)m_server->m_env.getMap());
133                         
134                 core::map<v3s16, MapBlock*> changed_blocks;
135                 core::map<v3s16, MapBlock*> lighting_invalidated_blocks;
136
137                 MapBlock *block = NULL;
138                 bool got_block = true;
139                 core::map<v3s16, MapBlock*> modified_blocks;
140                 
141                 {//envlock
142
143                 JMutexAutoLock envlock(m_server->m_env_mutex);
144
145                 //TimeTaker timer("block emerge envlock", g_device);
146                         
147                 try{
148                         bool only_from_disk = false;
149                         
150                         if(optional)
151                                 only_from_disk = true;
152
153                         block = map.emergeBlock(
154                                         p,
155                                         only_from_disk,
156                                         changed_blocks,
157                                         lighting_invalidated_blocks);
158                         
159                         // If it is a dummy, block was not found on disk
160                         if(block->isDummy())
161                         {
162                                 //dstream<<"EmergeThread: Got a dummy block"<<std::endl;
163                                 got_block = false;
164                         }
165                 }
166                 catch(InvalidPositionException &e)
167                 {
168                         // Block not found.
169                         // This happens when position is over limit.
170                         got_block = false;
171                 }
172                 
173                 if(got_block)
174                 {
175                         if(debug && changed_blocks.size() > 0)
176                         {
177                                 dout_server<<DTIME<<"Got changed_blocks: ";
178                                 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
179                                                 i.atEnd() == false; i++)
180                                 {
181                                         MapBlock *block = i.getNode()->getValue();
182                                         v3s16 p = block->getPos();
183                                         dout_server<<"("<<p.X<<","<<p.Y<<","<<p.Z<<") ";
184                                 }
185                                 dout_server<<std::endl;
186                         }
187
188                         /*
189                                 Collect a list of blocks that have been modified in
190                                 addition to the fetched one.
191                         */
192
193                         // Add all the "changed blocks"
194                         for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
195                                         i.atEnd() == false; i++)
196                         {
197                                 MapBlock *block = i.getNode()->getValue();
198                                 modified_blocks.insert(block->getPos(), block);
199
200                                 /*
201                                         Update water pressure.
202                                         This also adds suitable nodes to active_nodes.
203                                 */
204
205                                 MapVoxelManipulator v(&map);
206                                 
207                                 VoxelArea area(block->getPosRelative(),
208                                                 block->getPosRelative() + v3s16(1,1,1)*(MAP_BLOCKSIZE-1));
209
210                                 try
211                                 {
212                                         v.updateAreaWaterPressure(area, m_server->m_flow_active_nodes);
213                                 }
214                                 catch(ProcessingLimitException &e)
215                                 {
216                                         dstream<<"Processing limit reached (1)"<<std::endl;
217                                 }
218                                 
219                                 v.blitBack(modified_blocks);
220
221                         }
222                         
223                         /*dstream<<"lighting "<<lighting_invalidated_blocks.size()
224                                         <<" blocks"<<std::endl;
225                         TimeTaker timer("** updateLighting", g_device);*/
226                         
227                         // Update lighting without locking the environment mutex,
228                         // add modified blocks to changed blocks
229                         map.updateLighting(lighting_invalidated_blocks, modified_blocks);
230                 }
231                 // If we got no block, there should be no invalidated blocks
232                 else
233                 {
234                         assert(lighting_invalidated_blocks.size() == 0);
235                 }
236
237                 }//envlock
238
239                 /*
240                         Set sent status of modified blocks on clients
241                 */
242         
243                 // NOTE: Server's clients are also behind the connection mutex
244                 JMutexAutoLock lock(m_server->m_con_mutex);
245
246                 /*
247                         Add the originally fetched block to the modified list
248                 */
249                 if(got_block)
250                 {
251                         modified_blocks.insert(p, block);
252                 }
253                 
254                 /*
255                         Set the modified blocks unsent for all the clients
256                 */
257                 
258                 for(core::map<u16, RemoteClient*>::Iterator
259                                 i = m_server->m_clients.getIterator();
260                                 i.atEnd() == false; i++)
261                 {
262                         RemoteClient *client = i.getNode()->getValue();
263                         
264                         if(modified_blocks.size() > 0)
265                         {
266                                 // Remove block from sent history
267                                 client->SetBlocksNotSent(modified_blocks);
268                         }
269                 }
270                 
271         }
272 #if CATCH_UNHANDLED_EXCEPTIONS
273         }//try
274         /*
275                 This is what has to be done in threads to get suitable debug info
276         */
277         catch(std::exception &e)
278         {
279                 dstream<<std::endl<<DTIME<<"An unhandled exception occurred: "
280                                 <<e.what()<<std::endl;
281                 assert(0);
282         }
283 #endif
284
285         return NULL;
286 }
287
288 void RemoteClient::GetNextBlocks(Server *server, float dtime,
289                 core::array<PrioritySortedBlockTransfer> &dest)
290 {
291         DSTACK(__FUNCTION_NAME);
292         
293         // Won't send anything if already sending
294         {
295                 JMutexAutoLock lock(m_blocks_sending_mutex);
296                 
297                 if(m_blocks_sending.size() >= g_settings.getU16
298                                 ("max_simultaneous_block_sends_per_client"))
299                 {
300                         //dstream<<"Not sending any blocks, Queue full."<<std::endl;
301                         return;
302                 }
303         }
304
305         Player *player = server->m_env.getPlayer(peer_id);
306
307         v3f playerpos = player->getPosition();
308         v3f playerspeed = player->getSpeed();
309
310         v3s16 center_nodepos = floatToInt(playerpos);
311
312         v3s16 center = getNodeBlockPos(center_nodepos);
313
314         /*
315                 Get the starting value of the block finder radius.
316         */
317         s16 last_nearest_unsent_d;
318         s16 d_start;
319         {
320                 JMutexAutoLock lock(m_blocks_sent_mutex);
321                 
322                 if(m_last_center != center)
323                 {
324                         m_nearest_unsent_d = 0;
325                         m_last_center = center;
326                 }
327
328                 static float reset_counter = 0;
329                 reset_counter += dtime;
330                 if(reset_counter > 5.0)
331                 {
332                         reset_counter = 0;
333                         m_nearest_unsent_d = 0;
334                 }
335
336                 last_nearest_unsent_d = m_nearest_unsent_d;
337                 
338                 d_start = m_nearest_unsent_d;
339         }
340
341         u16 maximum_simultaneous_block_sends_setting = g_settings.getU16
342                         ("max_simultaneous_block_sends_per_client");
343         u16 maximum_simultaneous_block_sends = 
344                         maximum_simultaneous_block_sends_setting;
345
346         /*
347                 Check the time from last addNode/removeNode.
348                 
349                 Decrease send rate if player is building stuff.
350         */
351         {
352                 SharedPtr<JMutexAutoLock> lock(m_time_from_building.getLock());
353                 m_time_from_building.m_value += dtime;
354                 if(m_time_from_building.m_value
355                                 < FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING)
356                 {
357                         maximum_simultaneous_block_sends
358                                 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
359                 }
360         }
361
362         // Serialization version used
363         //u8 ser_version = serialization_version;
364
365         //bool has_incomplete_blocks = false;
366         
367         s16 d_max = g_settings.getS16("max_block_send_distance");
368         s16 d_max_gen = g_settings.getS16("max_block_generate_distance");
369         
370         //dstream<<"Starting from "<<d_start<<std::endl;
371
372         for(s16 d = d_start; d <= d_max; d++)
373         {
374                 //dstream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
375                 
376                 //if(has_incomplete_blocks == false)
377                 {
378                         JMutexAutoLock lock(m_blocks_sent_mutex);
379                         /*
380                                 If m_nearest_unsent_d was changed by the EmergeThread
381                                 (it can change it to 0 through SetBlockNotSent),
382                                 update our d to it.
383                                 Else update m_nearest_unsent_d
384                         */
385                         if(m_nearest_unsent_d != last_nearest_unsent_d)
386                         {
387                                 d = m_nearest_unsent_d;
388                         }
389                         else
390                         {
391                                 m_nearest_unsent_d = d;
392                         }
393                         last_nearest_unsent_d = m_nearest_unsent_d;
394                 }
395
396                 /*
397                         Get the border/face dot coordinates of a "d-radiused"
398                         box
399                 */
400                 core::list<v3s16> list;
401                 getFacePositions(list, d);
402                 
403                 core::list<v3s16>::Iterator li;
404                 for(li=list.begin(); li!=list.end(); li++)
405                 {
406                         v3s16 p = *li + center;
407                         
408                         /*
409                                 Send throttling
410                                 - Don't allow too many simultaneous transfers
411                                 - EXCEPT when the blocks are very close
412
413                                 Also, don't send blocks that are already flying.
414                         */
415                         
416                         u16 maximum_simultaneous_block_sends_now =
417                                         maximum_simultaneous_block_sends;
418                         
419                         if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
420                                         maximum_simultaneous_block_sends_now =
421                                                         maximum_simultaneous_block_sends_setting;
422
423                         {
424                                 JMutexAutoLock lock(m_blocks_sending_mutex);
425                                 
426                                 // Limit is dynamically lowered when building
427                                 if(m_blocks_sending.size()
428                                                 >= maximum_simultaneous_block_sends_now)
429                                 {
430                                         /*dstream<<"Not sending more blocks. Queue full. "
431                                                         <<m_blocks_sending.size()
432                                                         <<std::endl;*/
433                                         return;
434                                 }
435
436                                 if(m_blocks_sending.find(p) != NULL)
437                                         continue;
438                         }
439                         
440                         /*
441                                 Do not go over-limit
442                         */
443                         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
444                         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
445                         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
446                         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
447                         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
448                         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
449                                 continue;
450
451                         bool generate = d <= d_max_gen;
452                 
453                         // Limit the generating area vertically to half
454                         if(abs(p.Y - center.Y) > d_max_gen / 2)
455                                 generate = false;
456                         
457                         /*
458                                 Don't send already sent blocks
459                         */
460                         {
461                                 JMutexAutoLock lock(m_blocks_sent_mutex);
462                                 
463                                 if(m_blocks_sent.find(p) != NULL)
464                                         continue;
465                         }
466                                         
467                         /*
468                                 Check if map has this block
469                         */
470                         MapBlock *block = NULL;
471                         try
472                         {
473                                 block = server->m_env.getMap().getBlockNoCreate(p);
474                         }
475                         catch(InvalidPositionException &e)
476                         {
477                         }
478                         
479                         bool surely_not_found_on_disk = false;
480                         if(block != NULL)
481                         {
482                                 /*if(block->isIncomplete())
483                                 {
484                                         has_incomplete_blocks = true;
485                                         continue;
486                                 }*/
487
488                                 if(block->isDummy())
489                                 {
490                                         surely_not_found_on_disk = true;
491                                 }
492                         }
493
494                         /*
495                                 If block has been marked to not exist on disk (dummy)
496                                 and generating new ones is not wanted, skip block.
497                         */
498                         if(generate == false && surely_not_found_on_disk == true)
499                         {
500                                 // get next one.
501                                 continue;
502                         }
503
504                         /*
505                                 Add inexistent block to emerge queue.
506                         */
507                         if(block == NULL || surely_not_found_on_disk)
508                         {
509                                 /*SharedPtr<JMutexAutoLock> lock
510                                                 (m_num_blocks_in_emerge_queue.getLock());*/
511                                 
512                                 //TODO: Get value from somewhere
513                                 // Allow only one block in emerge queue
514                                 if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
515                                 {
516                                         // Add it to the emerge queue and trigger the thread
517                                         
518                                         u8 flags = 0;
519                                         if(generate == false)
520                                                 flags |= TOSERVER_GETBLOCK_FLAG_OPTIONAL;
521                                         
522                                         server->m_emerge_queue.addBlock(peer_id, p, flags);
523                                         server->m_emergethread.trigger();
524                                 }
525                                 
526                                 // get next one.
527                                 continue;
528                         }
529
530                         /*
531                                 Add block to queue
532                         */
533
534                         PrioritySortedBlockTransfer q((float)d, p, peer_id);
535
536                         dest.push_back(q);
537                 }
538         }
539
540         // Don't add anything here. The loop breaks by returning.
541 }
542
543 void RemoteClient::SendObjectData(
544                 Server *server,
545                 float dtime,
546                 core::map<v3s16, bool> &stepped_blocks
547         )
548 {
549         DSTACK(__FUNCTION_NAME);
550
551         // Can't send anything without knowing version
552         if(serialization_version == SER_FMT_VER_INVALID)
553         {
554                 dstream<<"RemoteClient::SendObjectData(): Not sending, no version."
555                                 <<std::endl;
556                 return;
557         }
558
559         /*
560                 Send a TOCLIENT_OBJECTDATA packet.
561                 Sent as unreliable.
562
563                 u16 command
564                 u16 number of player positions
565                 for each player:
566                         v3s32 position*100
567                         v3s32 speed*100
568                         s32 pitch*100
569                         s32 yaw*100
570                 u16 count of blocks
571                 for each block:
572                         block objects
573         */
574
575         std::ostringstream os(std::ios_base::binary);
576         u8 buf[12];
577         
578         // Write command
579         writeU16(buf, TOCLIENT_OBJECTDATA);
580         os.write((char*)buf, 2);
581         
582         /*
583                 Get and write player data
584         */
585
586         core::list<Player*> players = server->m_env.getPlayers();
587
588         // Write player count
589         u16 playercount = players.size();
590         writeU16(buf, playercount);
591         os.write((char*)buf, 2);
592
593         core::list<Player*>::Iterator i;
594         for(i = players.begin();
595                         i != players.end(); i++)
596         {
597                 Player *player = *i;
598
599                 v3f pf = player->getPosition();
600                 v3f sf = player->getSpeed();
601
602                 v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
603                 v3s32 speed_i   (sf.X*100, sf.Y*100, sf.Z*100);
604                 s32   pitch_i   (player->getPitch() * 100);
605                 s32   yaw_i     (player->getYaw() * 100);
606                 
607                 writeU16(buf, player->peer_id);
608                 os.write((char*)buf, 2);
609                 writeV3S32(buf, position_i);
610                 os.write((char*)buf, 12);
611                 writeV3S32(buf, speed_i);
612                 os.write((char*)buf, 12);
613                 writeS32(buf, pitch_i);
614                 os.write((char*)buf, 4);
615                 writeS32(buf, yaw_i);
616                 os.write((char*)buf, 4);
617         }
618         
619         /*
620                 Get and write object data
621         */
622
623         /*
624                 Get nearby blocks.
625                 
626                 For making players to be able to build to their nearby
627                 environment (building is not possible on blocks that are not
628                 in memory):
629                 - Set blocks changed
630                 - Add blocks to emerge queue if they are not found
631
632                 SUGGESTION: These could be ignored from the backside of the player
633
634                 TODO: Keep track of total size of packet and stop when it is too big
635         */
636
637         Player *player = server->m_env.getPlayer(peer_id);
638
639         v3f playerpos = player->getPosition();
640         v3f playerspeed = player->getSpeed();
641
642         v3s16 center_nodepos = floatToInt(playerpos);
643         v3s16 center = getNodeBlockPos(center_nodepos);
644
645         //s16 d_max = ACTIVE_OBJECT_D_BLOCKS;
646         s16 d_max = g_settings.getS16("active_object_range");
647         
648         // Number of blocks whose objects were written to bos
649         u16 blockcount = 0;
650
651         //core::map<v3s16, MapBlock*> blocks;
652         std::ostringstream bos(std::ios_base::binary);
653
654         for(s16 d = 0; d <= d_max; d++)
655         {
656                 core::list<v3s16> list;
657                 getFacePositions(list, d);
658                 
659                 core::list<v3s16>::Iterator li;
660                 for(li=list.begin(); li!=list.end(); li++)
661                 {
662                         v3s16 p = *li + center;
663
664                         /*
665                                 Ignore blocks that haven't been sent to the client
666                         */
667                         {
668                                 JMutexAutoLock sentlock(m_blocks_sent_mutex);
669                                 if(m_blocks_sent.find(p) == NULL)
670                                         continue;
671                         }
672                         
673                         // Try stepping block and add it to a send queue
674                         try
675                         {
676
677                         // Get block
678                         MapBlock *block = server->m_env.getMap().getBlockNoCreate(p);
679
680                         // Skip block if there are no objects
681                         if(block->getObjectCount() == 0)
682                                 continue;
683                         
684                         // Step block if not in stepped_blocks and add to stepped_blocks
685                         if(stepped_blocks.find(p) == NULL)
686                         {
687                                 block->stepObjects(dtime, true);
688                                 stepped_blocks.insert(p, true);
689                                 block->setChangedFlag();
690                         }
691
692                         /*
693                                 Write objects
694                         */
695
696                         // Write blockpos
697                         writeV3S16(buf, p);
698                         bos.write((char*)buf, 6);
699
700                         // Write objects
701                         block->serializeObjects(bos, serialization_version);
702
703                         blockcount++;
704
705                         /*
706                                 Stop collecting objects if data is already too big
707                         */
708                         // Sum of player and object data sizes
709                         s32 sum = (s32)os.tellp() + 2 + (s32)bos.tellp();
710                         // break out if data too big
711                         if(sum > MAX_OBJECTDATA_SIZE)
712                         {
713                                 goto skip_subsequent;
714                         }
715                         
716                         } //try
717                         catch(InvalidPositionException &e)
718                         {
719                                 // Not in memory
720                                 // Add it to the emerge queue and trigger the thread.
721                                 // Fetch the block only if it is on disk.
722                                 
723                                 // Grab and increment counter
724                                 /*SharedPtr<JMutexAutoLock> lock
725                                                 (m_num_blocks_in_emerge_queue.getLock());
726                                 m_num_blocks_in_emerge_queue.m_value++;*/
727                                 
728                                 // Add to queue as an anonymous fetch from disk
729                                 u8 flags = TOSERVER_GETBLOCK_FLAG_OPTIONAL;
730                                 server->m_emerge_queue.addBlock(0, p, flags);
731                                 server->m_emergethread.trigger();
732                         }
733                 }
734         }
735
736 skip_subsequent:
737
738         // Write block count
739         writeU16(buf, blockcount);
740         os.write((char*)buf, 2);
741
742         // Write block objects
743         os<<bos.str();
744
745         /*
746                 Send data
747         */
748         
749         //dstream<<"Server: Sending object data to "<<peer_id<<std::endl;
750
751         // Make data buffer
752         std::string s = os.str();
753         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
754         // Send as unreliable
755         server->m_con.Send(peer_id, 0, data, false);
756 }
757
758 void RemoteClient::GotBlock(v3s16 p)
759 {
760         JMutexAutoLock lock(m_blocks_sending_mutex);
761         JMutexAutoLock lock2(m_blocks_sent_mutex);
762         if(m_blocks_sending.find(p) != NULL)
763                 m_blocks_sending.remove(p);
764         else
765                 dstream<<"RemoteClient::GotBlock(): Didn't find in"
766                                 " m_blocks_sending"<<std::endl;
767         m_blocks_sent.insert(p, true);
768 }
769
770 void RemoteClient::SentBlock(v3s16 p)
771 {
772         JMutexAutoLock lock(m_blocks_sending_mutex);
773         if(m_blocks_sending.size() > 15)
774         {
775                 dstream<<"RemoteClient::SentBlock(): "
776                                 <<"m_blocks_sending.size()="
777                                 <<m_blocks_sending.size()<<std::endl;
778         }
779         if(m_blocks_sending.find(p) == NULL)
780                 m_blocks_sending.insert(p, 0.0);
781         else
782                 dstream<<"RemoteClient::SentBlock(): Sent block"
783                                 " already in m_blocks_sending"<<std::endl;
784 }
785
786 void RemoteClient::SetBlockNotSent(v3s16 p)
787 {
788         JMutexAutoLock sendinglock(m_blocks_sending_mutex);
789         JMutexAutoLock sentlock(m_blocks_sent_mutex);
790
791         m_nearest_unsent_d = 0;
792         
793         if(m_blocks_sending.find(p) != NULL)
794                 m_blocks_sending.remove(p);
795         if(m_blocks_sent.find(p) != NULL)
796                 m_blocks_sent.remove(p);
797 }
798
799 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
800 {
801         JMutexAutoLock sendinglock(m_blocks_sending_mutex);
802         JMutexAutoLock sentlock(m_blocks_sent_mutex);
803
804         m_nearest_unsent_d = 0;
805         
806         for(core::map<v3s16, MapBlock*>::Iterator
807                         i = blocks.getIterator();
808                         i.atEnd()==false; i++)
809         {
810                 v3s16 p = i.getNode()->getKey();
811
812                 if(m_blocks_sending.find(p) != NULL)
813                         m_blocks_sending.remove(p);
814                 if(m_blocks_sent.find(p) != NULL)
815                         m_blocks_sent.remove(p);
816         }
817 }
818
819 /*void RemoteClient::BlockEmerged()
820 {
821         SharedPtr<JMutexAutoLock> lock(m_num_blocks_in_emerge_queue.getLock());
822         assert(m_num_blocks_in_emerge_queue.m_value > 0);
823         m_num_blocks_in_emerge_queue.m_value--;
824 }*/
825
826 /*void RemoteClient::RunSendingTimeouts(float dtime, float timeout)
827 {
828         JMutexAutoLock sendinglock(m_blocks_sending_mutex);
829         
830         core::list<v3s16> remove_queue;
831         for(core::map<v3s16, float>::Iterator
832                         i = m_blocks_sending.getIterator();
833                         i.atEnd()==false; i++)
834         {
835                 v3s16 p = i.getNode()->getKey();
836                 float t = i.getNode()->getValue();
837                 t += dtime;
838                 i.getNode()->setValue(t);
839
840                 if(t > timeout)
841                 {
842                         remove_queue.push_back(p);
843                 }
844         }
845         for(core::list<v3s16>::Iterator
846                         i = remove_queue.begin();
847                         i != remove_queue.end(); i++)
848         {
849                 m_blocks_sending.remove(*i);
850         }
851 }*/
852
853 /*
854         PlayerInfo
855 */
856
857 PlayerInfo::PlayerInfo()
858 {
859         name[0] = 0;
860 }
861
862 void PlayerInfo::PrintLine(std::ostream *s)
863 {
864         (*s)<<id<<": \""<<name<<"\" ("
865                         <<position.X<<","<<position.Y
866                         <<","<<position.Z<<") ";
867         address.print(s);
868         (*s)<<" avg_rtt="<<avg_rtt;
869         (*s)<<std::endl;
870 }
871
872 u32 PIChecksum(core::list<PlayerInfo> &l)
873 {
874         core::list<PlayerInfo>::Iterator i;
875         u32 checksum = 1;
876         u32 a = 10;
877         for(i=l.begin(); i!=l.end(); i++)
878         {
879                 checksum += a * (i->id+1);
880                 checksum ^= 0x435aafcd;
881                 a *= 10;
882         }
883         return checksum;
884 }
885
886 /*
887         Server
888 */
889
890 Server::Server(
891                 std::string mapsavedir,
892                 HMParams hm_params,
893                 MapParams map_params
894         ):
895         m_env(new ServerMap(mapsavedir, hm_params, map_params), dout_server),
896         m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
897         m_thread(this),
898         m_emergethread(this)
899 {
900         m_env_mutex.Init();
901         m_con_mutex.Init();
902         m_step_dtime_mutex.Init();
903         m_step_dtime = 0.0;
904 }
905
906 Server::~Server()
907 {
908         // Stop threads
909         stop();
910
911         JMutexAutoLock clientslock(m_con_mutex);
912
913         for(core::map<u16, RemoteClient*>::Iterator
914                 i = m_clients.getIterator();
915                 i.atEnd() == false; i++)
916         {
917                 u16 peer_id = i.getNode()->getKey();
918
919                 // Delete player
920                 {
921                         JMutexAutoLock envlock(m_env_mutex);
922                         m_env.removePlayer(peer_id);
923                 }
924                 
925                 // Delete client
926                 delete i.getNode()->getValue();
927         }
928 }
929
930 void Server::start(unsigned short port)
931 {
932         DSTACK(__FUNCTION_NAME);
933         // Stop thread if already running
934         m_thread.stop();
935         
936         // Initialize connection
937         m_con.setTimeoutMs(30);
938         m_con.Serve(port);
939
940         // Start thread
941         m_thread.setRun(true);
942         m_thread.Start();
943         
944         dout_server<<"Server started on port "<<port<<std::endl;
945 }
946
947 void Server::stop()
948 {
949         DSTACK(__FUNCTION_NAME);
950         // Stop threads (set run=false first so both start stopping)
951         m_thread.setRun(false);
952         m_emergethread.setRun(false);
953         m_thread.stop();
954         m_emergethread.stop();
955         
956         dout_server<<"Server threads stopped"<<std::endl;
957 }
958
959 void Server::step(float dtime)
960 {
961         DSTACK(__FUNCTION_NAME);
962         // Limit a bit
963         if(dtime > 2.0)
964                 dtime = 2.0;
965         {
966                 JMutexAutoLock lock(m_step_dtime_mutex);
967                 m_step_dtime += dtime;
968         }
969 }
970
971 void Server::AsyncRunStep()
972 {
973         DSTACK(__FUNCTION_NAME);
974         
975         float dtime;
976         {
977                 JMutexAutoLock lock1(m_step_dtime_mutex);
978                 dtime = m_step_dtime;
979                 if(dtime < 0.001)
980                         return;
981                 m_step_dtime = 0.0;
982         }
983         
984         //dstream<<"Server steps "<<dtime<<std::endl;
985         
986         //dstream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
987         {
988                 // Has to be locked for peerAdded/Removed
989                 JMutexAutoLock lock1(m_env_mutex);
990                 // Process connection's timeouts
991                 JMutexAutoLock lock2(m_con_mutex);
992                 m_con.RunTimeouts(dtime);
993         }
994         {
995                 // Step environment
996                 // This also runs Map's timers
997                 JMutexAutoLock lock(m_env_mutex);
998                 m_env.step(dtime);
999         }
1000         
1001         /*
1002                 Do background stuff
1003         */
1004
1005         /*
1006                 Flow water
1007         */
1008         {
1009                 static float counter = 0.0;
1010                 counter += dtime;
1011                 if(counter >= 0.25 && m_flow_active_nodes.size() > 0)
1012                 {
1013                 
1014                 counter = 0.0;
1015
1016                 core::map<v3s16, MapBlock*> modified_blocks;
1017
1018                 {
1019
1020                         JMutexAutoLock lock(m_env_mutex);
1021                         
1022                         MapVoxelManipulator v(&m_env.getMap());
1023                         
1024                         v.flowWater(m_flow_active_nodes, 0, false, 50);
1025
1026                         v.blitBack(modified_blocks);
1027
1028                         ServerMap &map = ((ServerMap&)m_env.getMap());
1029                         
1030                         // Update lighting
1031                         core::map<v3s16, MapBlock*> lighting_modified_blocks;
1032                         map.updateLighting(modified_blocks, lighting_modified_blocks);
1033                         
1034                         // Add blocks modified by lighting to modified_blocks
1035                         for(core::map<v3s16, MapBlock*>::Iterator
1036                                         i = lighting_modified_blocks.getIterator();
1037                                         i.atEnd() == false; i++)
1038                         {
1039                                 MapBlock *block = i.getNode()->getValue();
1040                                 modified_blocks.insert(block->getPos(), block);
1041                         }
1042                 }
1043
1044                 /*
1045                         Set the modified blocks unsent for all the clients
1046                 */
1047                 
1048                 JMutexAutoLock lock2(m_con_mutex);
1049
1050                 for(core::map<u16, RemoteClient*>::Iterator
1051                                 i = m_clients.getIterator();
1052                                 i.atEnd() == false; i++)
1053                 {
1054                         RemoteClient *client = i.getNode()->getValue();
1055                         
1056                         if(modified_blocks.size() > 0)
1057                         {
1058                                 // Remove block from sent history
1059                                 client->SetBlocksNotSent(modified_blocks);
1060                         }
1061                 }
1062
1063                 } // interval counter
1064         }
1065         
1066         // Periodically print some info
1067         {
1068                 static float counter = 0.0;
1069                 counter += dtime;
1070                 if(counter >= 30.0)
1071                 {
1072                         counter = 0.0;
1073
1074                         JMutexAutoLock lock2(m_con_mutex);
1075
1076                         for(core::map<u16, RemoteClient*>::Iterator
1077                                 i = m_clients.getIterator();
1078                                 i.atEnd() == false; i++)
1079                         {
1080                                 //u16 peer_id = i.getNode()->getKey();
1081                                 RemoteClient *client = i.getNode()->getValue();
1082                                 client->PrintInfo(std::cout);
1083                         }
1084                 }
1085         }
1086
1087         // Run time- and client- related stuff
1088         // NOTE: If you intend to add something here, check that it
1089         // doesn't fit in RemoteClient::GetNextBlocks for example.
1090         /*{
1091                 // Clients are behind connection lock
1092                 JMutexAutoLock lock(m_con_mutex);
1093
1094                 for(core::map<u16, RemoteClient*>::Iterator
1095                         i = m_clients.getIterator();
1096                         i.atEnd() == false; i++)
1097                 {
1098                         RemoteClient *client = i.getNode()->getValue();
1099                         //con::Peer *peer = m_con.GetPeer(client->peer_id);
1100                         //client->RunSendingTimeouts(dtime, peer->resend_timeout);
1101                 }
1102         }*/
1103
1104         // Send blocks to clients
1105         SendBlocks(dtime);
1106         
1107         // Send object positions
1108         {
1109                 static float counter = 0.0;
1110                 counter += dtime;
1111                 if(counter >= g_settings.getFloat("objectdata_interval"))
1112                 {
1113                         JMutexAutoLock lock1(m_env_mutex);
1114                         JMutexAutoLock lock2(m_con_mutex);
1115                         SendObjectData(counter);
1116
1117                         counter = 0.0;
1118                 }
1119         }
1120         
1121         // Trigger emergethread (it gets somehow gets to a
1122         // non-triggered but bysy state sometimes)
1123         {
1124                 static float counter = 0.0;
1125                 counter += dtime;
1126                 if(counter >= 2.0)
1127                 {
1128                         counter = 0.0;
1129                         
1130                         m_emergethread.trigger();
1131                 }
1132         }
1133
1134         // Save map
1135         {
1136                 static float counter = 0.0;
1137                 counter += dtime;
1138                 if(counter >= SERVER_MAP_SAVE_INTERVAL)
1139                 {
1140                         counter = 0.0;
1141
1142                         JMutexAutoLock lock(m_env_mutex);
1143                         // Save only changed parts
1144                         m_env.getMap().save(true);
1145                 }
1146         }
1147 }
1148
1149 void Server::Receive()
1150 {
1151         DSTACK(__FUNCTION_NAME);
1152         u32 data_maxsize = 10000;
1153         Buffer<u8> data(data_maxsize);
1154         u16 peer_id;
1155         u32 datasize;
1156         try{
1157                 {
1158                         JMutexAutoLock lock(m_con_mutex);
1159                         datasize = m_con.Receive(peer_id, *data, data_maxsize);
1160                 }
1161                 ProcessData(*data, datasize, peer_id);
1162         }
1163         catch(con::InvalidIncomingDataException &e)
1164         {
1165                 derr_server<<"Server::Receive(): "
1166                                 "InvalidIncomingDataException: what()="
1167                                 <<e.what()<<std::endl;
1168         }
1169         catch(con::PeerNotFoundException &e)
1170         {
1171                 //NOTE: This is not needed anymore
1172                 
1173                 // The peer has been disconnected.
1174                 // Find the associated player and remove it.
1175
1176                 /*JMutexAutoLock envlock(m_env_mutex);
1177
1178                 dout_server<<"ServerThread: peer_id="<<peer_id
1179                                 <<" has apparently closed connection. "
1180                                 <<"Removing player."<<std::endl;
1181
1182                 m_env.removePlayer(peer_id);*/
1183         }
1184 }
1185
1186 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1187 {
1188         DSTACK(__FUNCTION_NAME);
1189         // Environment is locked first.
1190         JMutexAutoLock envlock(m_env_mutex);
1191         JMutexAutoLock conlock(m_con_mutex);
1192         
1193         con::Peer *peer;
1194         try{
1195                 peer = m_con.GetPeer(peer_id);
1196         }
1197         catch(con::PeerNotFoundException &e)
1198         {
1199                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1200                                 <<peer_id<<" not found"<<std::endl;
1201                 return;
1202         }
1203         
1204         //u8 peer_ser_ver = peer->serialization_version;
1205         u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1206
1207         try
1208         {
1209
1210         if(datasize < 2)
1211                 return;
1212
1213         ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1214         
1215         if(command == TOSERVER_INIT)
1216         {
1217                 // [0] u16 TOSERVER_INIT
1218                 // [2] u8 SER_FMT_VER_HIGHEST
1219                 // [3] u8[20] player_name
1220
1221                 if(datasize < 3)
1222                         return;
1223
1224                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1225                                 <<peer->id<<std::endl;
1226
1227                 // First byte after command is maximum supported
1228                 // serialization version
1229                 u8 client_max = data[2];
1230                 u8 our_max = SER_FMT_VER_HIGHEST;
1231                 // Use the highest version supported by both
1232                 u8 deployed = core::min_(client_max, our_max);
1233                 // If it's lower than the lowest supported, give up.
1234                 if(deployed < SER_FMT_VER_LOWEST)
1235                         deployed = SER_FMT_VER_INVALID;
1236
1237                 //peer->serialization_version = deployed;
1238                 getClient(peer->id)->pending_serialization_version = deployed;
1239
1240                 if(deployed == SER_FMT_VER_INVALID)
1241                 {
1242                         derr_server<<DTIME<<"Server: Cannot negotiate "
1243                                         "serialization version with peer "
1244                                         <<peer_id<<std::endl;
1245                         return;
1246                 }
1247
1248                 /*
1249                         Set up player
1250                 */
1251
1252                 Player *player = m_env.getPlayer(peer_id);
1253
1254                 // Check if player doesn't exist
1255                 if(player == NULL)
1256                         throw con::InvalidIncomingDataException
1257                                 ("Server::ProcessData(): INIT: Player doesn't exist");
1258
1259                 // update name if it was supplied
1260                 if(datasize >= 20+3)
1261                 {
1262                         data[20+3-1] = 0;
1263                         player->updateName((const char*)&data[3]);
1264                 }
1265
1266                 // Now answer with a TOCLIENT_INIT
1267                 
1268                 SharedBuffer<u8> reply(2+1+6);
1269                 writeU16(&reply[0], TOCLIENT_INIT);
1270                 writeU8(&reply[2], deployed);
1271                 writeV3S16(&reply[3], floatToInt(player->getPosition()+v3f(0,BS/2,0)));
1272                 // Send as reliable
1273                 m_con.Send(peer_id, 0, reply, true);
1274
1275                 return;
1276         }
1277         if(command == TOSERVER_INIT2)
1278         {
1279                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
1280                                 <<peer->id<<std::endl;
1281
1282
1283                 getClient(peer->id)->serialization_version
1284                                 = getClient(peer->id)->pending_serialization_version;
1285
1286                 /*
1287                         Send some initialization data
1288                 */
1289                 
1290                 // Send player info to all players
1291                 SendPlayerInfos();
1292
1293                 // Send inventory to player
1294                 SendInventory(peer->id);
1295
1296                 return;
1297         }
1298
1299         if(peer_ser_ver == SER_FMT_VER_INVALID)
1300         {
1301                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
1302                                 " serialization format invalid or not initialized."
1303                                 " Skipping incoming command="<<command<<std::endl;
1304                 return;
1305         }
1306         
1307         Player *player = m_env.getPlayer(peer_id);
1308
1309         if(player == NULL){
1310                 derr_server<<"Server::ProcessData(): Cancelling: "
1311                                 "No player for peer_id="<<peer_id
1312                                 <<std::endl;
1313                 return;
1314         }
1315         if(command == TOSERVER_PLAYERPOS)
1316         {
1317                 if(datasize < 2+12+12+4+4)
1318                         return;
1319         
1320                 u32 start = 0;
1321                 v3s32 ps = readV3S32(&data[start+2]);
1322                 v3s32 ss = readV3S32(&data[start+2+12]);
1323                 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1324                 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1325                 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1326                 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1327                 pitch = wrapDegrees(pitch);
1328                 yaw = wrapDegrees(yaw);
1329                 player->setPosition(position);
1330                 player->setSpeed(speed);
1331                 player->setPitch(pitch);
1332                 player->setYaw(yaw);
1333                 
1334                 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1335                                 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1336                                 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1337         }
1338         else if(command == TOSERVER_GOTBLOCKS)
1339         {
1340                 if(datasize < 2+1)
1341                         return;
1342                 
1343                 /*
1344                         [0] u16 command
1345                         [2] u8 count
1346                         [3] v3s16 pos_0
1347                         [3+6] v3s16 pos_1
1348                         ...
1349                 */
1350
1351                 u16 count = data[2];
1352                 for(u16 i=0; i<count; i++)
1353                 {
1354                         if((s16)datasize < 2+1+(i+1)*6)
1355                                 throw con::InvalidIncomingDataException
1356                                         ("GOTBLOCKS length is too short");
1357                         v3s16 p = readV3S16(&data[2+1+i*6]);
1358                         /*dstream<<"Server: GOTBLOCKS ("
1359                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1360                         RemoteClient *client = getClient(peer_id);
1361                         client->GotBlock(p);
1362                 }
1363         }
1364         else if(command == TOSERVER_DELETEDBLOCKS)
1365         {
1366                 if(datasize < 2+1)
1367                         return;
1368                 
1369                 /*
1370                         [0] u16 command
1371                         [2] u8 count
1372                         [3] v3s16 pos_0
1373                         [3+6] v3s16 pos_1
1374                         ...
1375                 */
1376
1377                 u16 count = data[2];
1378                 for(u16 i=0; i<count; i++)
1379                 {
1380                         if((s16)datasize < 2+1+(i+1)*6)
1381                                 throw con::InvalidIncomingDataException
1382                                         ("DELETEDBLOCKS length is too short");
1383                         v3s16 p = readV3S16(&data[2+1+i*6]);
1384                         /*dstream<<"Server: DELETEDBLOCKS ("
1385                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1386                         RemoteClient *client = getClient(peer_id);
1387                         client->SetBlockNotSent(p);
1388                 }
1389         }
1390         else if(command == TOSERVER_CLICK_OBJECT)
1391         {
1392                 if(datasize < 13)
1393                         return;
1394
1395                 /*
1396                         [0] u16 command
1397                         [2] u8 button (0=left, 1=right)
1398                         [3] v3s16 block
1399                         [9] s16 id
1400                         [11] u16 item
1401                 */
1402                 u8 button = readU8(&data[2]);
1403                 v3s16 p;
1404                 p.X = readS16(&data[3]);
1405                 p.Y = readS16(&data[5]);
1406                 p.Z = readS16(&data[7]);
1407                 s16 id = readS16(&data[9]);
1408                 //u16 item_i = readU16(&data[11]);
1409
1410                 MapBlock *block = NULL;
1411                 try
1412                 {
1413                         block = m_env.getMap().getBlockNoCreate(p);
1414                 }
1415                 catch(InvalidPositionException &e)
1416                 {
1417                         derr_server<<"PICK_OBJECT block not found"<<std::endl;
1418                         return;
1419                 }
1420
1421                 MapBlockObject *obj = block->getObject(id);
1422
1423                 if(obj == NULL)
1424                 {
1425                         derr_server<<"PICK_OBJECT object not found"<<std::endl;
1426                         return;
1427                 }
1428
1429                 //TODO: Check that object is reasonably close
1430                 
1431                 // Left click
1432                 if(button == 0)
1433                 {
1434                         if(g_settings.getBool("creative_mode") == false)
1435                         {
1436                         
1437                                 // Skip if inventory has no free space
1438                                 if(player->inventory.getUsedSlots() == player->inventory.getSize())
1439                                 {
1440                                         dout_server<<"Player inventory has no free space"<<std::endl;
1441                                         return;
1442                                 }
1443                         
1444                                 // Add to inventory and send inventory
1445                                 InventoryItem *item = new MapBlockObjectItem
1446                                                 (obj->getInventoryString());
1447                                 player->inventory.addItem(item);
1448                                 SendInventory(player->peer_id);
1449                         }
1450
1451                         // Remove from block
1452                         block->removeObject(id);
1453                 }
1454         }
1455         else if(command == TOSERVER_CLICK_GROUND)
1456         {
1457                 if(datasize < 17)
1458                         return;
1459                 /*
1460                         length: 17
1461                         [0] u16 command
1462                         [2] u8 button (0=left, 1=right)
1463                         [3] v3s16 nodepos_undersurface
1464                         [9] v3s16 nodepos_abovesurface
1465                         [15] u16 item
1466                 */
1467                 u8 button = readU8(&data[2]);
1468                 v3s16 p_under;
1469                 p_under.X = readS16(&data[3]);
1470                 p_under.Y = readS16(&data[5]);
1471                 p_under.Z = readS16(&data[7]);
1472                 v3s16 p_over;
1473                 p_over.X = readS16(&data[9]);
1474                 p_over.Y = readS16(&data[11]);
1475                 p_over.Z = readS16(&data[13]);
1476                 u16 item_i = readU16(&data[15]);
1477
1478                 //TODO: Check that target is reasonably close
1479                 
1480                 /*
1481                         Left button digs ground
1482                 */
1483                 if(button == 0)
1484                 {
1485
1486                         core::map<v3s16, MapBlock*> modified_blocks;
1487
1488                         u8 material;
1489
1490                         try
1491                         {
1492                                 // Get material at position
1493                                 material = m_env.getMap().getNode(p_under).d;
1494                                 // If it's not diggable, do nothing
1495                                 if(material_diggable(material) == false)
1496                                 {
1497                                         return;
1498                                 }
1499                         }
1500                         catch(InvalidPositionException &e)
1501                         {
1502                                 derr_server<<"Server: Ignoring REMOVENODE: Node not found"
1503                                                 <<std::endl;
1504                                 return;
1505                         }
1506                         
1507                         // Reset build time counter
1508                         getClient(peer->id)->m_time_from_building.set(0.0);
1509                         
1510                         // Create packet
1511                         u32 replysize = 8;
1512                         SharedBuffer<u8> reply(replysize);
1513                         writeU16(&reply[0], TOCLIENT_REMOVENODE);
1514                         writeS16(&reply[2], p_under.X);
1515                         writeS16(&reply[4], p_under.Y);
1516                         writeS16(&reply[6], p_under.Z);
1517                         // Send as reliable
1518                         m_con.SendToAll(0, reply, true);
1519                         
1520                         if(g_settings.getBool("creative_mode") == false)
1521                         {
1522                                 // Add to inventory and send inventory
1523                                 InventoryItem *item = new MaterialItem(material, 1);
1524                                 player->inventory.addItem(item);
1525                                 SendInventory(player->peer_id);
1526                         }
1527
1528                         /*
1529                                 Remove the node
1530                                 (this takes some time so it is done after the quick stuff)
1531                         */
1532                         m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
1533                         
1534                         /*
1535                                 Update water
1536                         */
1537                         
1538                         // Update water pressure around modification
1539                         // This also adds it to m_flow_active_nodes if appropriate
1540
1541                         MapVoxelManipulator v(&m_env.getMap());
1542                         
1543                         VoxelArea area(p_under-v3s16(1,1,1), p_under+v3s16(1,1,1));
1544
1545                         try
1546                         {
1547                                 v.updateAreaWaterPressure(area, m_flow_active_nodes);
1548                         }
1549                         catch(ProcessingLimitException &e)
1550                         {
1551                                 dstream<<"Processing limit reached (1)"<<std::endl;
1552                         }
1553                         
1554                         v.blitBack(modified_blocks);
1555                         
1556                         // Add the node to m_flow_active_nodes.
1557                         //m_flow_active_nodes[p_under] = 1;
1558
1559                 } // button == 0
1560                 /*
1561                         Right button places blocks and stuff
1562                 */
1563                 else if(button == 1)
1564                 {
1565
1566                         // Get item
1567                         InventoryItem *item = player->inventory.getItem(item_i);
1568                         
1569                         // If there is no item, it is not possible to add it anywhere
1570                         if(item == NULL)
1571                                 return;
1572                         
1573                         /*
1574                                 Handle material items
1575                         */
1576                         if(std::string("MaterialItem") == item->getName())
1577                         {
1578                                 MaterialItem *mitem = (MaterialItem*)item;
1579                                 
1580                                 MapNode n;
1581                                 n.d = mitem->getMaterial();
1582
1583                                 try{
1584                                         // Don't add a node if this is not a free space
1585                                         MapNode n2 = m_env.getMap().getNode(p_over);
1586                                         if(material_buildable_to(n2.d) == false)
1587                                                 return;
1588                                 }
1589                                 catch(InvalidPositionException &e)
1590                                 {
1591                                         derr_server<<"Server: Ignoring ADDNODE: Node not found"
1592                                                         <<std::endl;
1593                                         return;
1594                                 }
1595
1596                                 // Reset build time counter
1597                                 getClient(peer->id)->m_time_from_building.set(0.0);
1598                                 
1599                                 if(g_settings.getBool("creative_mode") == false)
1600                                 {
1601                                         // Remove from inventory and send inventory
1602                                         if(mitem->getCount() == 1)
1603                                                 player->inventory.deleteItem(item_i);
1604                                         else
1605                                                 mitem->remove(1);
1606                                         // Send inventory
1607                                         SendInventory(peer_id);
1608                                 }
1609                                 
1610                                 // Create packet
1611                                 u32 replysize = 8 + MapNode::serializedLength(peer_ser_ver);
1612                                 SharedBuffer<u8> reply(replysize);
1613                                 writeU16(&reply[0], TOCLIENT_ADDNODE);
1614                                 writeS16(&reply[2], p_over.X);
1615                                 writeS16(&reply[4], p_over.Y);
1616                                 writeS16(&reply[6], p_over.Z);
1617                                 n.serialize(&reply[8], peer_ser_ver);
1618                                 // Send as reliable
1619                                 m_con.SendToAll(0, reply, true);
1620                                 
1621                                 /*
1622                                         Add node.
1623
1624                                         This takes some time so it is done after the quick stuff
1625                                 */
1626                                 core::map<v3s16, MapBlock*> modified_blocks;
1627                                 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
1628                                 
1629                                 /*
1630                                         Update water
1631                                 */
1632                                 
1633                                 // Update water pressure around modification
1634                                 // This also adds it to m_flow_active_nodes if appropriate
1635
1636                                 MapVoxelManipulator v(&m_env.getMap());
1637                                 
1638                                 VoxelArea area(p_over-v3s16(1,1,1), p_over+v3s16(1,1,1));
1639
1640                                 try
1641                                 {
1642                                         v.updateAreaWaterPressure(area, m_flow_active_nodes);
1643                                 }
1644                                 catch(ProcessingLimitException &e)
1645                                 {
1646                                         dstream<<"Processing limit reached (1)"<<std::endl;
1647                                 }
1648                                 
1649                                 v.blitBack(modified_blocks);
1650                         }
1651                         /*
1652                                 Handle block object items
1653                         */
1654                         else if(std::string("MBOItem") == item->getName())
1655                         {
1656                                 MapBlockObjectItem *oitem = (MapBlockObjectItem*)item;
1657
1658                                 /*dout_server<<"Trying to place a MapBlockObjectItem: "
1659                                                 "inventorystring=\""
1660                                                 <<oitem->getInventoryString()
1661                                                 <<"\""<<std::endl;*/
1662
1663                                 v3s16 blockpos = getNodeBlockPos(p_over);
1664
1665                                 MapBlock *block = NULL;
1666                                 try
1667                                 {
1668                                         block = m_env.getMap().getBlockNoCreate(blockpos);
1669                                 }
1670                                 catch(InvalidPositionException &e)
1671                                 {
1672                                         derr_server<<"Error while placing object: "
1673                                                         "block not found"<<std::endl;
1674                                         return;
1675                                 }
1676
1677                                 v3s16 block_pos_i_on_map = block->getPosRelative();
1678                                 v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map);
1679
1680                                 v3f pos = intToFloat(p_over);
1681                                 pos -= block_pos_f_on_map;
1682                                 
1683                                 /*dout_server<<"pos="
1684                                                 <<"("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1685                                                 <<std::endl;*/
1686
1687
1688                                 MapBlockObject *obj = oitem->createObject
1689                                                 (pos, player->getYaw(), player->getPitch());
1690
1691                                 if(obj == NULL)
1692                                         derr_server<<"WARNING: oitem created NULL object"
1693                                                         <<std::endl;
1694
1695                                 block->addObject(obj);
1696
1697                                 //dout_server<<"Placed object"<<std::endl;
1698
1699                                 if(g_settings.getBool("creative_mode") == false)
1700                                 {
1701                                         // Remove from inventory and send inventory
1702                                         player->inventory.deleteItem(item_i);
1703                                         // Send inventory
1704                                         SendInventory(peer_id);
1705                                 }
1706                         }
1707
1708                 } // button == 1
1709                 /*
1710                         Catch invalid buttons
1711                 */
1712                 else
1713                 {
1714                         derr_server<<"WARNING: Server: Invalid button "
1715                                         <<button<<std::endl;
1716                 }
1717         }
1718         else if(command == TOSERVER_RELEASE)
1719         {
1720                 if(datasize < 3)
1721                         return;
1722                 /*
1723                         length: 3
1724                         [0] u16 command
1725                         [2] u8 button
1726                 */
1727                 //TODO
1728         }
1729         else if(command == TOSERVER_SIGNTEXT)
1730         {
1731                 /*
1732                         u16 command
1733                         v3s16 blockpos
1734                         s16 id
1735                         u16 textlen
1736                         textdata
1737                 */
1738                 std::string datastring((char*)&data[2], datasize-2);
1739                 std::istringstream is(datastring, std::ios_base::binary);
1740                 u8 buf[6];
1741                 // Read stuff
1742                 is.read((char*)buf, 6);
1743                 v3s16 blockpos = readV3S16(buf);
1744                 is.read((char*)buf, 2);
1745                 s16 id = readS16(buf);
1746                 is.read((char*)buf, 2);
1747                 u16 textlen = readU16(buf);
1748                 std::string text;
1749                 for(u16 i=0; i<textlen; i++)
1750                 {
1751                         is.read((char*)buf, 1);
1752                         text += (char)buf[0];
1753                 }
1754
1755                 MapBlock *block = NULL;
1756                 try
1757                 {
1758                         block = m_env.getMap().getBlockNoCreate(blockpos);
1759                 }
1760                 catch(InvalidPositionException &e)
1761                 {
1762                         derr_server<<"Error while setting sign text: "
1763                                         "block not found"<<std::endl;
1764                         return;
1765                 }
1766
1767                 MapBlockObject *obj = block->getObject(id);
1768                 if(obj == NULL)
1769                 {
1770                         derr_server<<"Error while setting sign text: "
1771                                         "object not found"<<std::endl;
1772                         return;
1773                 }
1774                 
1775                 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
1776                 {
1777                         derr_server<<"Error while setting sign text: "
1778                                         "object is not a sign"<<std::endl;
1779                         return;
1780                 }
1781
1782                 ((SignObject*)obj)->setText(text);
1783
1784                 obj->getBlock()->setChangedFlag();
1785         }
1786         else
1787         {
1788                 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
1789                                 "unknown command "<<command<<std::endl;
1790         }
1791         
1792         } //try
1793         catch(SendFailedException &e)
1794         {
1795                 derr_server<<"Server::ProcessData(): SendFailedException: "
1796                                 <<"what="<<e.what()
1797                                 <<std::endl;
1798         }
1799 }
1800
1801 /*void Server::Send(u16 peer_id, u16 channelnum,
1802                 SharedBuffer<u8> data, bool reliable)
1803 {
1804         JMutexAutoLock lock(m_con_mutex);
1805         m_con.Send(peer_id, channelnum, data, reliable);
1806 }*/
1807
1808 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
1809 {
1810         DSTACK(__FUNCTION_NAME);
1811         /*
1812                 Create a packet with the block in the right format
1813         */
1814         
1815         std::ostringstream os(std::ios_base::binary);
1816         block->serialize(os, ver);
1817         std::string s = os.str();
1818         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
1819
1820         u32 replysize = 8 + blockdata.getSize();
1821         SharedBuffer<u8> reply(replysize);
1822         v3s16 p = block->getPos();
1823         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
1824         writeS16(&reply[2], p.X);
1825         writeS16(&reply[4], p.Y);
1826         writeS16(&reply[6], p.Z);
1827         memcpy(&reply[8], *blockdata, blockdata.getSize());
1828         
1829         /*
1830                 Send packet
1831         */
1832         m_con.Send(peer_id, 1, reply, true);
1833 }
1834
1835 /*void Server::SendBlock(u16 peer_id, MapBlock *block, u8 ver)
1836 {
1837         JMutexAutoLock conlock(m_con_mutex);
1838         
1839         SendBlockNoLock(peer_id, block, ver);
1840 }*/
1841
1842 #if 0
1843 void Server::SendSectorMeta(u16 peer_id, core::list<v2s16> ps, u8 ver)
1844 {
1845         DSTACK(__FUNCTION_NAME);
1846         dstream<<"Server sending sector meta of "
1847                         <<ps.getSize()<<" sectors"<<std::endl;
1848
1849         core::list<v2s16>::Iterator i = ps.begin();
1850         core::list<v2s16> sendlist;
1851         for(;;)
1852         {
1853                 if(sendlist.size() == 255 || i == ps.end())
1854                 {
1855                         if(sendlist.size() == 0)
1856                                 break;
1857                         /*
1858                                 [0] u16 command
1859                                 [2] u8 sector count
1860                                 [3...] v2s16 pos + sector metadata
1861                         */
1862                         std::ostringstream os(std::ios_base::binary);
1863                         u8 buf[4];
1864
1865                         writeU16(buf, TOCLIENT_SECTORMETA);
1866                         os.write((char*)buf, 2);
1867
1868                         writeU8(buf, sendlist.size());
1869                         os.write((char*)buf, 1);
1870
1871                         for(core::list<v2s16>::Iterator
1872                                         j = sendlist.begin();
1873                                         j != sendlist.end(); j++)
1874                         {
1875                                 // Write position
1876                                 writeV2S16(buf, *j);
1877                                 os.write((char*)buf, 4);
1878                                 
1879                                 /*
1880                                         Write ClientMapSector metadata
1881                                 */
1882
1883                                 /*
1884                                         [0] u8 serialization version
1885                                         [1] s16 corners[0]
1886                                         [3] s16 corners[1]
1887                                         [5] s16 corners[2]
1888                                         [7] s16 corners[3]
1889                                         size = 9
1890                                         
1891                                         In which corners are in these positions
1892                                         v2s16(0,0),
1893                                         v2s16(1,0),
1894                                         v2s16(1,1),
1895                                         v2s16(0,1),
1896                                 */
1897
1898                                 // Write version
1899                                 writeU8(buf, ver);
1900                                 os.write((char*)buf, 1);
1901
1902                                 // Write corners
1903                                 // TODO: Get real values
1904                                 s16 corners[4];
1905                                 ((ServerMap&)m_env.getMap()).getSectorCorners(*j, corners);
1906
1907                                 writeS16(buf, corners[0]);
1908                                 os.write((char*)buf, 2);
1909                                 writeS16(buf, corners[1]);
1910                                 os.write((char*)buf, 2);
1911                                 writeS16(buf, corners[2]);
1912                                 os.write((char*)buf, 2);
1913                                 writeS16(buf, corners[3]);
1914                                 os.write((char*)buf, 2);
1915                         }
1916
1917                         SharedBuffer<u8> data((u8*)os.str().c_str(), os.str().size());
1918
1919                         /*dstream<<"Server::SendSectorMeta(): sending packet"
1920                                         " with "<<sendlist.size()<<" sectors"<<std::endl;*/
1921
1922                         m_con.Send(peer_id, 1, data, true);
1923
1924                         if(i == ps.end())
1925                                 break;
1926
1927                         sendlist.clear();
1928                 }
1929
1930                 sendlist.push_back(*i);
1931                 i++;
1932         }
1933 }
1934 #endif
1935
1936 core::list<PlayerInfo> Server::getPlayerInfo()
1937 {
1938         DSTACK(__FUNCTION_NAME);
1939         JMutexAutoLock envlock(m_env_mutex);
1940         JMutexAutoLock conlock(m_con_mutex);
1941         
1942         core::list<PlayerInfo> list;
1943
1944         core::list<Player*> players = m_env.getPlayers();
1945         
1946         core::list<Player*>::Iterator i;
1947         for(i = players.begin();
1948                         i != players.end(); i++)
1949         {
1950                 PlayerInfo info;
1951
1952                 Player *player = *i;
1953                 try{
1954                         con::Peer *peer = m_con.GetPeer(player->peer_id);
1955                         info.id = peer->id;
1956                         info.address = peer->address;
1957                         info.avg_rtt = peer->avg_rtt;
1958                 }
1959                 catch(con::PeerNotFoundException &e)
1960                 {
1961                         // Outdated peer info
1962                         info.id = 0;
1963                         info.address = Address(0,0,0,0,0);
1964                         info.avg_rtt = 0.0;
1965                 }
1966
1967                 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
1968                 info.position = player->getPosition();
1969
1970                 list.push_back(info);
1971         }
1972
1973         return list;
1974 }
1975
1976 void Server::peerAdded(con::Peer *peer)
1977 {
1978         DSTACK(__FUNCTION_NAME);
1979         dout_server<<"Server::peerAdded(): peer->id="
1980                         <<peer->id<<std::endl;
1981         
1982         // Connection is already locked when this is called.
1983         //JMutexAutoLock lock(m_con_mutex);
1984         
1985         // Error check
1986         core::map<u16, RemoteClient*>::Node *n;
1987         n = m_clients.find(peer->id);
1988         // The client shouldn't already exist
1989         assert(n == NULL);
1990
1991         // Create client
1992         RemoteClient *client = new RemoteClient();
1993         client->peer_id = peer->id;
1994         m_clients.insert(client->peer_id, client);
1995
1996         // Create player
1997         {
1998                 // Already locked when called
1999                 //JMutexAutoLock envlock(m_env_mutex);
2000                 
2001                 Player *player = m_env.getPlayer(peer->id);
2002                 
2003                 // The player shouldn't already exist
2004                 assert(player == NULL);
2005
2006                 player = new RemotePlayer();
2007                 player->peer_id = peer->id;
2008
2009                 /*
2010                         Set player position
2011                 */
2012
2013                 // Get zero sector (it could have been unloaded to disk)
2014                 m_env.getMap().emergeSector(v2s16(0,0));
2015                 // Get ground height at origin
2016                 f32 groundheight = m_env.getMap().getGroundHeight(v2s16(0,0), true);
2017                 // The zero sector should have been generated
2018                 assert(groundheight > GROUNDHEIGHT_VALID_MINVALUE);
2019                 // Don't go underwater
2020                 if(groundheight < WATER_LEVEL)
2021                         groundheight = WATER_LEVEL;
2022
2023                 player->setPosition(intToFloat(v3s16(
2024                                 0,
2025                                 groundheight + 1,
2026                                 0
2027                 )));
2028
2029                 /*
2030                         Add player to environment
2031                 */
2032
2033                 m_env.addPlayer(player);
2034
2035                 /*
2036                         Add stuff to inventory
2037                 */
2038                 
2039                 if(g_settings.getBool("creative_mode"))
2040                 {
2041                         // Give all materials
2042                         assert(USEFUL_MATERIAL_COUNT <= PLAYER_INVENTORY_SIZE);
2043                         for(u16 i=0; i<USEFUL_MATERIAL_COUNT; i++)
2044                         {
2045                                 // Skip some materials
2046                                 if(i == MATERIAL_OCEAN)
2047                                         continue;
2048
2049                                 InventoryItem *item = new MaterialItem(i, 1);
2050                                 player->inventory.addItem(item);
2051                         }
2052                         // Sign
2053                         {
2054                                 InventoryItem *item = new MapBlockObjectItem("Sign Example text");
2055                                 bool r = player->inventory.addItem(item);
2056                                 assert(r == true);
2057                         }
2058                         /*// Rat
2059                         {
2060                                 InventoryItem *item = new MapBlockObjectItem("Rat");
2061                                 bool r = player->inventory.addItem(item);
2062                                 assert(r == true);
2063                         }*/
2064                 }
2065                 else
2066                 {
2067                         // Give some lights
2068                         {
2069                                 InventoryItem *item = new MaterialItem(3, 999);
2070                                 bool r = player->inventory.addItem(item);
2071                                 assert(r == true);
2072                         }
2073                         // and some signs
2074                         for(u16 i=0; i<4; i++)
2075                         {
2076                                 InventoryItem *item = new MapBlockObjectItem("Sign Example text");
2077                                 bool r = player->inventory.addItem(item);
2078                                 assert(r == true);
2079                         }
2080                         /*// and some rats
2081                         for(u16 i=0; i<4; i++)
2082                         {
2083                                 InventoryItem *item = new MapBlockObjectItem("Rat");
2084                                 bool r = player->inventory.addItem(item);
2085                                 assert(r == true);
2086                         }*/
2087                 }
2088         }
2089 }
2090
2091 void Server::deletingPeer(con::Peer *peer, bool timeout)
2092 {
2093         DSTACK(__FUNCTION_NAME);
2094         dout_server<<"Server::deletingPeer(): peer->id="
2095                         <<peer->id<<", timeout="<<timeout<<std::endl;
2096         
2097         // Connection is already locked when this is called.
2098         //JMutexAutoLock lock(m_con_mutex);
2099
2100         // Error check
2101         core::map<u16, RemoteClient*>::Node *n;
2102         n = m_clients.find(peer->id);
2103         // The client should exist
2104         assert(n != NULL);
2105         
2106         // Delete player
2107         {
2108                 // Already locked when called
2109                 //JMutexAutoLock envlock(m_env_mutex);
2110                 m_env.removePlayer(peer->id);
2111         }
2112         
2113         // Delete client
2114         delete m_clients[peer->id];
2115         m_clients.remove(peer->id);
2116
2117         // Send player info to all clients
2118         SendPlayerInfos();
2119 }
2120
2121 void Server::SendObjectData(float dtime)
2122 {
2123         DSTACK(__FUNCTION_NAME);
2124
2125         core::map<v3s16, bool> stepped_blocks;
2126         
2127         for(core::map<u16, RemoteClient*>::Iterator
2128                 i = m_clients.getIterator();
2129                 i.atEnd() == false; i++)
2130         {
2131                 u16 peer_id = i.getNode()->getKey();
2132                 RemoteClient *client = i.getNode()->getValue();
2133                 assert(client->peer_id == peer_id);
2134                 
2135                 if(client->serialization_version == SER_FMT_VER_INVALID)
2136                         continue;
2137                 
2138                 client->SendObjectData(this, dtime, stepped_blocks);
2139         }
2140 }
2141
2142 void Server::SendPlayerInfos()
2143 {
2144         DSTACK(__FUNCTION_NAME);
2145
2146         //JMutexAutoLock envlock(m_env_mutex);
2147         
2148         core::list<Player*> players = m_env.getPlayers();
2149         
2150         u32 player_count = players.getSize();
2151         u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
2152
2153         SharedBuffer<u8> data(datasize);
2154         writeU16(&data[0], TOCLIENT_PLAYERINFO);
2155         
2156         u32 start = 2;
2157         core::list<Player*>::Iterator i;
2158         for(i = players.begin();
2159                         i != players.end(); i++)
2160         {
2161                 Player *player = *i;
2162
2163                 /*dstream<<"Server sending player info for player with "
2164                                 "peer_id="<<player->peer_id<<std::endl;*/
2165                 
2166                 writeU16(&data[start], player->peer_id);
2167                 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
2168                 start += 2+PLAYERNAME_SIZE;
2169         }
2170
2171         //JMutexAutoLock conlock(m_con_mutex);
2172
2173         // Send as reliable
2174         m_con.SendToAll(0, data, true);
2175 }
2176
2177 void Server::SendInventory(u16 peer_id)
2178 {
2179         DSTACK(__FUNCTION_NAME);
2180         
2181         //JMutexAutoLock envlock(m_env_mutex);
2182         
2183         Player* player = m_env.getPlayer(peer_id);
2184
2185         std::ostringstream os;
2186         //os.imbue(std::locale("C"));
2187
2188         player->inventory.serialize(os);
2189
2190         std::string s = os.str();
2191         
2192         SharedBuffer<u8> data(s.size()+2);
2193         writeU16(&data[0], TOCLIENT_INVENTORY);
2194         memcpy(&data[2], s.c_str(), s.size());
2195         
2196         //JMutexAutoLock conlock(m_con_mutex);
2197
2198         // Send as reliable
2199         m_con.Send(peer_id, 0, data, true);
2200 }
2201
2202 void Server::SendBlocks(float dtime)
2203 {
2204         DSTACK(__FUNCTION_NAME);
2205
2206         JMutexAutoLock envlock(m_env_mutex);
2207
2208         core::array<PrioritySortedBlockTransfer> queue;
2209
2210         s32 total_sending = 0;
2211
2212         for(core::map<u16, RemoteClient*>::Iterator
2213                 i = m_clients.getIterator();
2214                 i.atEnd() == false; i++)
2215         {
2216                 RemoteClient *client = i.getNode()->getValue();
2217                 assert(client->peer_id == i.getNode()->getKey());
2218
2219                 total_sending += client->SendingCount();
2220                 
2221                 if(client->serialization_version == SER_FMT_VER_INVALID)
2222                         continue;
2223                 
2224                 client->GetNextBlocks(this, dtime, queue);
2225         }
2226
2227         // Sort.
2228         // Lowest priority number comes first.
2229         // Lowest is most important.
2230         queue.sort();
2231
2232         JMutexAutoLock conlock(m_con_mutex);
2233
2234         for(u32 i=0; i<queue.size(); i++)
2235         {
2236                 //TODO: Calculate limit dynamically
2237                 if(total_sending >= g_settings.getS32
2238                                 ("max_simultaneous_block_sends_server_total"))
2239                         break;
2240                 
2241                 PrioritySortedBlockTransfer q = queue[i];
2242
2243                 MapBlock *block = NULL;
2244                 try
2245                 {
2246                         block = m_env.getMap().getBlockNoCreate(q.pos);
2247                 }
2248                 catch(InvalidPositionException &e)
2249                 {
2250                         continue;
2251                 }
2252
2253                 RemoteClient *client = getClient(q.peer_id);
2254
2255                 SendBlockNoLock(q.peer_id, block, client->serialization_version);
2256
2257                 client->SentBlock(q.pos);
2258
2259                 total_sending++;
2260         }
2261 }
2262
2263
2264 RemoteClient* Server::getClient(u16 peer_id)
2265 {
2266         DSTACK(__FUNCTION_NAME);
2267         //JMutexAutoLock lock(m_con_mutex);
2268         core::map<u16, RemoteClient*>::Node *n;
2269         n = m_clients.find(peer_id);
2270         // A client should exist for all peers
2271         assert(n != NULL);
2272         return n->getValue();
2273 }
2274
2275