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