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