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