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