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