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