]> git.lizzy.rs Git - minetest.git/blob - src/server.cpp
better support for old maps
[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 #include "server.h"
21 #include "utility.h"
22 #include <iostream>
23 #include "clientserver.h"
24 #include "map.h"
25 #include "jmutexautolock.h"
26 #include "main.h"
27 #include "constants.h"
28 #include "voxel.h"
29 #include "materials.h"
30 #include "mineral.h"
31
32 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
33
34 void * ServerThread::Thread()
35 {
36         ThreadStarted();
37
38         DSTACK(__FUNCTION_NAME);
39
40         BEGIN_DEBUG_EXCEPTION_HANDLER
41
42         while(getRun())
43         {
44                 try{
45                         //TimeTaker timer("AsyncRunStep() + Receive()");
46
47                         {
48                                 //TimeTaker timer("AsyncRunStep()");
49                                 m_server->AsyncRunStep();
50                         }
51                 
52                         //dout_server<<"Running m_server->Receive()"<<std::endl;
53                         m_server->Receive();
54                 }
55                 catch(con::NoIncomingDataException &e)
56                 {
57                 }
58                 catch(con::PeerNotFoundException &e)
59                 {
60                         dout_server<<"Server: PeerNotFoundException"<<std::endl;
61                 }
62         }
63         
64         END_DEBUG_EXCEPTION_HANDLER
65
66         return NULL;
67 }
68
69 void * EmergeThread::Thread()
70 {
71         ThreadStarted();
72
73         DSTACK(__FUNCTION_NAME);
74
75         //bool debug=false;
76         
77         BEGIN_DEBUG_EXCEPTION_HANDLER
78
79         /*
80                 Get block info from queue, emerge them and send them
81                 to clients.
82
83                 After queue is empty, exit.
84         */
85         while(getRun())
86         {
87                 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
88                 if(qptr == NULL)
89                         break;
90                 
91                 SharedPtr<QueuedBlockEmerge> q(qptr);
92
93                 v3s16 &p = q->pos;
94                 v2s16 p2d(p.X,p.Z);
95
96                 /*
97                         Do not generate over-limit
98                 */
99                 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
100                 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
101                 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
102                 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
103                 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
104                 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
105                         continue;
106                         
107                 //derr_server<<"EmergeThread::Thread(): running"<<std::endl;
108
109                 //TimeTaker timer("block emerge");
110                 
111                 /*
112                         Try to emerge it from somewhere.
113
114                         If it is only wanted as optional, only loading from disk
115                         will be allowed.
116                 */
117                 
118                 /*
119                         Check if any peer wants it as non-optional. In that case it
120                         will be generated.
121
122                         Also decrement the emerge queue count in clients.
123                 */
124
125                 bool optional = true;
126
127                 {
128                         core::map<u16, u8>::Iterator i;
129                         for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
130                         {
131                                 //u16 peer_id = i.getNode()->getKey();
132
133                                 // Check flags
134                                 u8 flags = i.getNode()->getValue();
135                                 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
136                                         optional = false;
137                                 
138                         }
139                 }
140
141                 /*dstream<<"EmergeThread: p="
142                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
143                                 <<"optional="<<optional<<std::endl;*/
144                 
145                 ServerMap &map = ((ServerMap&)m_server->m_env.getMap());
146                         
147                 core::map<v3s16, MapBlock*> changed_blocks;
148                 core::map<v3s16, MapBlock*> lighting_invalidated_blocks;
149
150                 MapBlock *block = NULL;
151                 bool got_block = true;
152                 core::map<v3s16, MapBlock*> modified_blocks;
153                 
154                 bool only_from_disk = false;
155                 
156                 if(optional)
157                         only_from_disk = true;
158
159                 v2s16 chunkpos = map.sector_to_chunk(p2d);
160
161                 bool generate_chunk = false;
162                 if(only_from_disk == false)
163                 {
164                         JMutexAutoLock envlock(m_server->m_env_mutex);
165                         if(map.chunkNonVolatile(chunkpos) == false)
166                                 generate_chunk = true;
167                 }
168                 if(generate_chunk)
169                 {
170                         ChunkMakeData data;
171                         
172                         {
173                                 JMutexAutoLock envlock(m_server->m_env_mutex);
174                                 map.initChunkMake(data, chunkpos);
175                         }
176
177                         makeChunk(&data);
178
179                         {
180                                 JMutexAutoLock envlock(m_server->m_env_mutex);
181                                 map.finishChunkMake(data, changed_blocks);
182                         }
183                 }
184         
185                 /*
186                         Fetch block from map or generate a single block
187                 */
188                 {
189                         JMutexAutoLock envlock(m_server->m_env_mutex);
190                         
191                         // Load sector if it isn't loaded
192                         if(map.getSectorNoGenerateNoEx(p2d) == NULL)
193                                 map.loadSectorFull(p2d);
194
195                         block = map.getBlockNoCreateNoEx(p);
196                         if(!block || block->isDummy())
197                         {
198                                 if(only_from_disk)
199                                 {
200                                         got_block = false;
201                                 }
202                                 else
203                                 {
204                                         // Get, load or create sector
205                                         ServerMapSector *sector =
206                                                         (ServerMapSector*)map.createSector(p2d);
207                                         // Generate block
208                                         block = map.generateBlock(p, block, sector, changed_blocks,
209                                                         lighting_invalidated_blocks);
210                                         if(block == NULL)
211                                                 got_block = false;
212                                 }
213                         }
214                         else
215                         {
216                                 if(block->getLightingExpired()){
217                                         lighting_invalidated_blocks[block->getPos()] = block;
218                                 }
219                         }
220
221                         // TODO: Some additional checking and lighting updating,
222                         // see emergeBlock
223                 }
224
225                 {//envlock
226                 JMutexAutoLock envlock(m_server->m_env_mutex);
227                 
228                 if(got_block)
229                 {
230                         /*
231                                 Collect a list of blocks that have been modified in
232                                 addition to the fetched one.
233                         */
234                         
235                         if(lighting_invalidated_blocks.size() > 0)
236                         {
237                                 /*dstream<<"lighting "<<lighting_invalidated_blocks.size()
238                                                 <<" blocks"<<std::endl;*/
239                         
240                                 // 50-100ms for single block generation
241                                 //TimeTaker timer("** EmergeThread updateLighting");
242                                 
243                                 // Update lighting without locking the environment mutex,
244                                 // add modified blocks to changed blocks
245                                 map.updateLighting(lighting_invalidated_blocks, modified_blocks);
246                         }
247                                 
248                         // Add all from changed_blocks to modified_blocks
249                         for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
250                                         i.atEnd() == false; i++)
251                         {
252                                 MapBlock *block = i.getNode()->getValue();
253                                 modified_blocks.insert(block->getPos(), block);
254                         }
255                 }
256                 // If we got no block, there should be no invalidated blocks
257                 else
258                 {
259                         assert(lighting_invalidated_blocks.size() == 0);
260                 }
261
262                 }//envlock
263
264                 /*
265                         Set sent status of modified blocks on clients
266                 */
267         
268                 // NOTE: Server's clients are also behind the connection mutex
269                 JMutexAutoLock lock(m_server->m_con_mutex);
270
271                 /*
272                         Add the originally fetched block to the modified list
273                 */
274                 if(got_block)
275                 {
276                         modified_blocks.insert(p, block);
277                 }
278                 
279                 /*
280                         Set the modified blocks unsent for all the clients
281                 */
282                 
283                 for(core::map<u16, RemoteClient*>::Iterator
284                                 i = m_server->m_clients.getIterator();
285                                 i.atEnd() == false; i++)
286                 {
287                         RemoteClient *client = i.getNode()->getValue();
288                         
289                         if(modified_blocks.size() > 0)
290                         {
291                                 // Remove block from sent history
292                                 client->SetBlocksNotSent(modified_blocks);
293                         }
294                 }
295                 
296         }
297
298         END_DEBUG_EXCEPTION_HANDLER
299
300         return NULL;
301 }
302
303 void RemoteClient::GetNextBlocks(Server *server, float dtime,
304                 core::array<PrioritySortedBlockTransfer> &dest)
305 {
306         DSTACK(__FUNCTION_NAME);
307         
308         // Increment timers
309         m_nearest_unsent_reset_timer += dtime;
310
311         // Won't send anything if already sending
312         if(m_blocks_sending.size() >= g_settings.getU16
313                         ("max_simultaneous_block_sends_per_client"))
314         {
315                 //dstream<<"Not sending any blocks, Queue full."<<std::endl;
316                 return;
317         }
318
319         Player *player = server->m_env.getPlayer(peer_id);
320
321         assert(player != NULL);
322
323         v3f playerpos = player->getPosition();
324         v3f playerspeed = player->getSpeed();
325
326         v3s16 center_nodepos = floatToInt(playerpos, BS);
327
328         v3s16 center = getNodeBlockPos(center_nodepos);
329         
330         // Camera position and direction
331         v3f camera_pos =
332                         playerpos + v3f(0, BS+BS/2, 0);
333         v3f camera_dir = v3f(0,0,1);
334         camera_dir.rotateYZBy(player->getPitch());
335         camera_dir.rotateXZBy(player->getYaw());
336
337         /*
338                 Get the starting value of the block finder radius.
339         */
340         s16 last_nearest_unsent_d;
341         s16 d_start;
342                 
343         if(m_last_center != center)
344         {
345                 m_nearest_unsent_d = 0;
346                 m_last_center = center;
347         }
348
349         /*dstream<<"m_nearest_unsent_reset_timer="
350                         <<m_nearest_unsent_reset_timer<<std::endl;*/
351         if(m_nearest_unsent_reset_timer > 5.0)
352         {
353                 m_nearest_unsent_reset_timer = 0;
354                 m_nearest_unsent_d = 0;
355                 //dstream<<"Resetting m_nearest_unsent_d"<<std::endl;
356         }
357
358         last_nearest_unsent_d = m_nearest_unsent_d;
359         
360         d_start = m_nearest_unsent_d;
361
362         u16 maximum_simultaneous_block_sends_setting = g_settings.getU16
363                         ("max_simultaneous_block_sends_per_client");
364         u16 maximum_simultaneous_block_sends = 
365                         maximum_simultaneous_block_sends_setting;
366
367         /*
368                 Check the time from last addNode/removeNode.
369                 
370                 Decrease send rate if player is building stuff.
371         */
372         m_time_from_building += dtime;
373         if(m_time_from_building < g_settings.getFloat(
374                                 "full_block_send_enable_min_time_from_building"))
375         {
376                 maximum_simultaneous_block_sends
377                         = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
378         }
379         
380         u32 num_blocks_selected = m_blocks_sending.size();
381         
382         /*
383                 next time d will be continued from the d from which the nearest
384                 unsent block was found this time.
385
386                 This is because not necessarily any of the blocks found this
387                 time are actually sent.
388         */
389         s32 new_nearest_unsent_d = -1;
390
391         s16 d_max = g_settings.getS16("max_block_send_distance");
392         s16 d_max_gen = g_settings.getS16("max_block_generate_distance");
393         
394         //dstream<<"Starting from "<<d_start<<std::endl;
395
396         for(s16 d = d_start; d <= d_max; d++)
397         {
398                 //dstream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
399                 
400                 /*
401                         If m_nearest_unsent_d was changed by the EmergeThread
402                         (it can change it to 0 through SetBlockNotSent),
403                         update our d to it.
404                         Else update m_nearest_unsent_d
405                 */
406                 if(m_nearest_unsent_d != last_nearest_unsent_d)
407                 {
408                         d = m_nearest_unsent_d;
409                         last_nearest_unsent_d = m_nearest_unsent_d;
410                 }
411
412                 /*
413                         Get the border/face dot coordinates of a "d-radiused"
414                         box
415                 */
416                 core::list<v3s16> list;
417                 getFacePositions(list, d);
418                 
419                 core::list<v3s16>::Iterator li;
420                 for(li=list.begin(); li!=list.end(); li++)
421                 {
422                         v3s16 p = *li + center;
423                         
424                         /*
425                                 Send throttling
426                                 - Don't allow too many simultaneous transfers
427                                 - EXCEPT when the blocks are very close
428
429                                 Also, don't send blocks that are already flying.
430                         */
431                         
432                         u16 maximum_simultaneous_block_sends_now =
433                                         maximum_simultaneous_block_sends;
434                         
435                         if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
436                         {
437                                 maximum_simultaneous_block_sends_now =
438                                                 maximum_simultaneous_block_sends_setting;
439                         }
440
441                         // Limit is dynamically lowered when building
442                         if(num_blocks_selected
443                                         >= maximum_simultaneous_block_sends_now)
444                         {
445                                 /*dstream<<"Not sending more blocks. Queue full. "
446                                                 <<m_blocks_sending.size()
447                                                 <<std::endl;*/
448                                 goto queue_full;
449                         }
450
451                         if(m_blocks_sending.find(p) != NULL)
452                                 continue;
453                 
454                         /*
455                                 Do not go over-limit
456                         */
457                         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
458                         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
459                         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
460                         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
461                         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
462                         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
463                                 continue;
464                 
465                         // If this is true, inexistent block will be made from scratch
466                         bool generate = d <= d_max_gen;
467                         
468                         {
469                                 /*// Limit the generating area vertically to 2/3
470                                 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
471                                         generate = false;*/
472
473                                 // Limit the send area vertically to 2/3
474                                 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
475                                         continue;
476                         }
477
478 #if 0
479                         /*
480                                 If block is far away, don't generate it unless it is
481                                 near ground level
482
483                                 NOTE: We can't know the ground level this way with the
484                                 new generator.
485                         */
486                         if(d > 4)
487                         {
488                                 v2s16 p2d(p.X, p.Z);
489                                 MapSector *sector = NULL;
490                                 try
491                                 {
492                                         sector = server->m_env.getMap().getSectorNoGenerate(p2d);
493                                 }
494                                 catch(InvalidPositionException &e)
495                                 {
496                                 }
497
498                                 if(sector != NULL)
499                                 {
500                                         // Get center ground height in nodes
501                                         f32 gh = sector->getGroundHeight(
502                                                         v2s16(MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2));
503                                         // Block center y in nodes
504                                         f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
505                                         // If differs a lot, don't generate
506                                         if(fabs(gh - y) > MAP_BLOCKSIZE*2)
507                                                 generate = false;
508                                 }
509                         }
510 #endif
511
512                         /*
513                                 Don't generate or send if not in sight
514                         */
515
516                         if(isBlockInSight(p, camera_pos, camera_dir, 10000*BS) == false)
517                         {
518                                 continue;
519                         }
520                         
521                         /*
522                                 Don't send already sent blocks
523                         */
524                         {
525                                 if(m_blocks_sent.find(p) != NULL)
526                                         continue;
527                         }
528
529                         /*
530                                 Check if map has this block
531                         */
532                         MapBlock *block = server->m_env.getMap().getBlockNoCreateNoEx(p);
533                         
534                         bool surely_not_found_on_disk = false;
535                         bool block_is_invalid = false;
536                         if(block != NULL)
537                         {
538                                 if(block->isDummy())
539                                 {
540                                         surely_not_found_on_disk = true;
541                                 }
542
543                                 if(block->isValid() == false)
544                                 {
545                                         block_is_invalid = true;
546                                 }
547                                 
548                                 /*if(block->isFullyGenerated() == false)
549                                 {
550                                         block_is_invalid = true;
551                                 }*/
552                                 
553                                 v2s16 p2d(p.X, p.Z);
554                                 ServerMap *map = (ServerMap*)(&server->m_env.getMap());
555                                 v2s16 chunkpos = map->sector_to_chunk(p2d);
556                                 if(map->chunkNonVolatile(chunkpos) == false)
557                                         block_is_invalid = true;
558                         }
559
560                         /*
561                                 If block has been marked to not exist on disk (dummy)
562                                 and generating new ones is not wanted, skip block.
563                         */
564                         if(generate == false && surely_not_found_on_disk == true)
565                         {
566                                 // get next one.
567                                 continue;
568                         }
569
570                         /*
571                                 Record the lowest d from which a a block has been
572                                 found being not sent and possibly to exist
573                         */
574                         if(new_nearest_unsent_d == -1 || d < new_nearest_unsent_d)
575                         {
576                                 new_nearest_unsent_d = d;
577                         }
578                                         
579                         /*
580                                 Add inexistent block to emerge queue.
581                         */
582                         if(block == NULL || surely_not_found_on_disk || block_is_invalid)
583                         {
584                                 //TODO: Get value from somewhere
585                                 // Allow only one block in emerge queue
586                                 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
587                                 if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
588                                 {
589                                         //dstream<<"Adding block to emerge queue"<<std::endl;
590                                         
591                                         // Add it to the emerge queue and trigger the thread
592                                         
593                                         u8 flags = 0;
594                                         if(generate == false)
595                                                 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
596                                         
597                                         server->m_emerge_queue.addBlock(peer_id, p, flags);
598                                         server->m_emergethread.trigger();
599                                 }
600                                 
601                                 // get next one.
602                                 continue;
603                         }
604
605                         /*
606                                 Add block to send queue
607                         */
608
609                         PrioritySortedBlockTransfer q((float)d, p, peer_id);
610
611                         dest.push_back(q);
612
613                         num_blocks_selected += 1;
614                 }
615         }
616 queue_full:
617
618         if(new_nearest_unsent_d != -1)
619         {
620                 m_nearest_unsent_d = new_nearest_unsent_d;
621         }
622 }
623
624 void RemoteClient::SendObjectData(
625                 Server *server,
626                 float dtime,
627                 core::map<v3s16, bool> &stepped_blocks
628         )
629 {
630         DSTACK(__FUNCTION_NAME);
631
632         // Can't send anything without knowing version
633         if(serialization_version == SER_FMT_VER_INVALID)
634         {
635                 dstream<<"RemoteClient::SendObjectData(): Not sending, no version."
636                                 <<std::endl;
637                 return;
638         }
639
640         /*
641                 Send a TOCLIENT_OBJECTDATA packet.
642                 Sent as unreliable.
643
644                 u16 command
645                 u16 number of player positions
646                 for each player:
647                         v3s32 position*100
648                         v3s32 speed*100
649                         s32 pitch*100
650                         s32 yaw*100
651                 u16 count of blocks
652                 for each block:
653                         block objects
654         */
655
656         std::ostringstream os(std::ios_base::binary);
657         u8 buf[12];
658         
659         // Write command
660         writeU16(buf, TOCLIENT_OBJECTDATA);
661         os.write((char*)buf, 2);
662         
663         /*
664                 Get and write player data
665         */
666         
667         // Get connected players
668         core::list<Player*> players = server->m_env.getPlayers(true);
669
670         // Write player count
671         u16 playercount = players.size();
672         writeU16(buf, playercount);
673         os.write((char*)buf, 2);
674
675         core::list<Player*>::Iterator i;
676         for(i = players.begin();
677                         i != players.end(); i++)
678         {
679                 Player *player = *i;
680
681                 v3f pf = player->getPosition();
682                 v3f sf = player->getSpeed();
683
684                 v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
685                 v3s32 speed_i   (sf.X*100, sf.Y*100, sf.Z*100);
686                 s32   pitch_i   (player->getPitch() * 100);
687                 s32   yaw_i     (player->getYaw() * 100);
688                 
689                 writeU16(buf, player->peer_id);
690                 os.write((char*)buf, 2);
691                 writeV3S32(buf, position_i);
692                 os.write((char*)buf, 12);
693                 writeV3S32(buf, speed_i);
694                 os.write((char*)buf, 12);
695                 writeS32(buf, pitch_i);
696                 os.write((char*)buf, 4);
697                 writeS32(buf, yaw_i);
698                 os.write((char*)buf, 4);
699         }
700         
701         /*
702                 Get and write object data
703         */
704
705         /*
706                 Get nearby blocks.
707                 
708                 For making players to be able to build to their nearby
709                 environment (building is not possible on blocks that are not
710                 in memory):
711                 - Set blocks changed
712                 - Add blocks to emerge queue if they are not found
713
714                 SUGGESTION: These could be ignored from the backside of the player
715         */
716
717         Player *player = server->m_env.getPlayer(peer_id);
718
719         assert(player);
720
721         v3f playerpos = player->getPosition();
722         v3f playerspeed = player->getSpeed();
723
724         v3s16 center_nodepos = floatToInt(playerpos, BS);
725         v3s16 center = getNodeBlockPos(center_nodepos);
726
727         s16 d_max = g_settings.getS16("active_object_range");
728         
729         // Number of blocks whose objects were written to bos
730         u16 blockcount = 0;
731
732         std::ostringstream bos(std::ios_base::binary);
733
734         for(s16 d = 0; d <= d_max; d++)
735         {
736                 core::list<v3s16> list;
737                 getFacePositions(list, d);
738                 
739                 core::list<v3s16>::Iterator li;
740                 for(li=list.begin(); li!=list.end(); li++)
741                 {
742                         v3s16 p = *li + center;
743
744                         /*
745                                 Ignore blocks that haven't been sent to the client
746                         */
747                         {
748                                 if(m_blocks_sent.find(p) == NULL)
749                                         continue;
750                         }
751                         
752                         // Try stepping block and add it to a send queue
753                         try
754                         {
755
756                         // Get block
757                         MapBlock *block = server->m_env.getMap().getBlockNoCreate(p);
758
759                         /*
760                                 Step block if not in stepped_blocks and add to stepped_blocks.
761                         */
762                         if(stepped_blocks.find(p) == NULL)
763                         {
764                                 block->stepObjects(dtime, true, server->getDayNightRatio());
765                                 stepped_blocks.insert(p, true);
766                                 block->setChangedFlag();
767                         }
768
769                         // Skip block if there are no objects
770                         if(block->getObjectCount() == 0)
771                                 continue;
772                         
773                         /*
774                                 Write objects
775                         */
776
777                         // Write blockpos
778                         writeV3S16(buf, p);
779                         bos.write((char*)buf, 6);
780
781                         // Write objects
782                         block->serializeObjects(bos, serialization_version);
783
784                         blockcount++;
785
786                         /*
787                                 Stop collecting objects if data is already too big
788                         */
789                         // Sum of player and object data sizes
790                         s32 sum = (s32)os.tellp() + 2 + (s32)bos.tellp();
791                         // break out if data too big
792                         if(sum > MAX_OBJECTDATA_SIZE)
793                         {
794                                 goto skip_subsequent;
795                         }
796                         
797                         } //try
798                         catch(InvalidPositionException &e)
799                         {
800                                 // Not in memory
801                                 // Add it to the emerge queue and trigger the thread.
802                                 // Fetch the block only if it is on disk.
803                                 
804                                 // Grab and increment counter
805                                 /*SharedPtr<JMutexAutoLock> lock
806                                                 (m_num_blocks_in_emerge_queue.getLock());
807                                 m_num_blocks_in_emerge_queue.m_value++;*/
808                                 
809                                 // Add to queue as an anonymous fetch from disk
810                                 u8 flags = BLOCK_EMERGE_FLAG_FROMDISK;
811                                 server->m_emerge_queue.addBlock(0, p, flags);
812                                 server->m_emergethread.trigger();
813                         }
814                 }
815         }
816
817 skip_subsequent:
818
819         // Write block count
820         writeU16(buf, blockcount);
821         os.write((char*)buf, 2);
822
823         // Write block objects
824         os<<bos.str();
825
826         /*
827                 Send data
828         */
829         
830         //dstream<<"Server: Sending object data to "<<peer_id<<std::endl;
831
832         // Make data buffer
833         std::string s = os.str();
834         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
835         // Send as unreliable
836         server->m_con.Send(peer_id, 0, data, false);
837 }
838
839 void RemoteClient::GotBlock(v3s16 p)
840 {
841         if(m_blocks_sending.find(p) != NULL)
842                 m_blocks_sending.remove(p);
843         else
844         {
845                 /*dstream<<"RemoteClient::GotBlock(): Didn't find in"
846                                 " m_blocks_sending"<<std::endl;*/
847                 m_excess_gotblocks++;
848         }
849         m_blocks_sent.insert(p, true);
850 }
851
852 void RemoteClient::SentBlock(v3s16 p)
853 {
854         if(m_blocks_sending.find(p) == NULL)
855                 m_blocks_sending.insert(p, 0.0);
856         else
857                 dstream<<"RemoteClient::SentBlock(): Sent block"
858                                 " already in m_blocks_sending"<<std::endl;
859 }
860
861 void RemoteClient::SetBlockNotSent(v3s16 p)
862 {
863         m_nearest_unsent_d = 0;
864         
865         if(m_blocks_sending.find(p) != NULL)
866                 m_blocks_sending.remove(p);
867         if(m_blocks_sent.find(p) != NULL)
868                 m_blocks_sent.remove(p);
869 }
870
871 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
872 {
873         m_nearest_unsent_d = 0;
874         
875         for(core::map<v3s16, MapBlock*>::Iterator
876                         i = blocks.getIterator();
877                         i.atEnd()==false; i++)
878         {
879                 v3s16 p = i.getNode()->getKey();
880
881                 if(m_blocks_sending.find(p) != NULL)
882                         m_blocks_sending.remove(p);
883                 if(m_blocks_sent.find(p) != NULL)
884                         m_blocks_sent.remove(p);
885         }
886 }
887
888 /*
889         PlayerInfo
890 */
891
892 PlayerInfo::PlayerInfo()
893 {
894         name[0] = 0;
895 }
896
897 void PlayerInfo::PrintLine(std::ostream *s)
898 {
899         (*s)<<id<<": ";
900         (*s)<<"\""<<name<<"\" ("
901                         <<(position.X/10)<<","<<(position.Y/10)
902                         <<","<<(position.Z/10)<<") ";
903         address.print(s);
904         (*s)<<" avg_rtt="<<avg_rtt;
905         (*s)<<std::endl;
906 }
907
908 u32 PIChecksum(core::list<PlayerInfo> &l)
909 {
910         core::list<PlayerInfo>::Iterator i;
911         u32 checksum = 1;
912         u32 a = 10;
913         for(i=l.begin(); i!=l.end(); i++)
914         {
915                 checksum += a * (i->id+1);
916                 checksum ^= 0x435aafcd;
917                 a *= 10;
918         }
919         return checksum;
920 }
921
922 /*
923         Server
924 */
925
926 Server::Server(
927                 std::string mapsavedir
928         ):
929         m_env(new ServerMap(mapsavedir), this),
930         m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
931         m_thread(this),
932         m_emergethread(this),
933         m_time_of_day(9000),
934         m_time_counter(0),
935         m_time_of_day_send_timer(0),
936         m_uptime(0),
937         m_mapsavedir(mapsavedir),
938         m_shutdown_requested(false),
939         m_ignore_map_edit_events(false),
940         m_ignore_map_edit_events_peer_id(0)
941 {
942         m_liquid_transform_timer = 0.0;
943         m_print_info_timer = 0.0;
944         m_objectdata_timer = 0.0;
945         m_emergethread_trigger_timer = 0.0;
946         m_savemap_timer = 0.0;
947         
948         m_env_mutex.Init();
949         m_con_mutex.Init();
950         m_step_dtime_mutex.Init();
951         m_step_dtime = 0.0;
952
953         m_env.getMap().addEventReceiver(this);
954
955         // Load players
956         m_env.deSerializePlayers(m_mapsavedir);
957 }
958
959 Server::~Server()
960 {
961         /*
962                 Send shutdown message
963         */
964         {
965                 JMutexAutoLock conlock(m_con_mutex);
966                 
967                 std::wstring line = L"*** Server shutting down";
968
969                 /*
970                         Send the message to clients
971                 */
972                 for(core::map<u16, RemoteClient*>::Iterator
973                         i = m_clients.getIterator();
974                         i.atEnd() == false; i++)
975                 {
976                         // Get client and check that it is valid
977                         RemoteClient *client = i.getNode()->getValue();
978                         assert(client->peer_id == i.getNode()->getKey());
979                         if(client->serialization_version == SER_FMT_VER_INVALID)
980                                 continue;
981
982                         SendChatMessage(client->peer_id, line);
983                 }
984         }
985
986         /*
987                 Save players
988         */
989         m_env.serializePlayers(m_mapsavedir);
990         
991         /*
992                 Stop threads
993         */
994         stop();
995         
996         /*
997                 Delete clients
998         */
999         {
1000                 JMutexAutoLock clientslock(m_con_mutex);
1001
1002                 for(core::map<u16, RemoteClient*>::Iterator
1003                         i = m_clients.getIterator();
1004                         i.atEnd() == false; i++)
1005                 {
1006                         /*// Delete player
1007                         // NOTE: These are removed by env destructor
1008                         {
1009                                 u16 peer_id = i.getNode()->getKey();
1010                                 JMutexAutoLock envlock(m_env_mutex);
1011                                 m_env.removePlayer(peer_id);
1012                         }*/
1013                         
1014                         // Delete client
1015                         delete i.getNode()->getValue();
1016                 }
1017         }
1018 }
1019
1020 void Server::start(unsigned short port)
1021 {
1022         DSTACK(__FUNCTION_NAME);
1023         // Stop thread if already running
1024         m_thread.stop();
1025         
1026         // Initialize connection
1027         m_con.setTimeoutMs(30);
1028         m_con.Serve(port);
1029
1030         // Start thread
1031         m_thread.setRun(true);
1032         m_thread.Start();
1033         
1034         dout_server<<"Server: Started on port "<<port<<std::endl;
1035 }
1036
1037 void Server::stop()
1038 {
1039         DSTACK(__FUNCTION_NAME);
1040
1041         // Stop threads (set run=false first so both start stopping)
1042         m_thread.setRun(false);
1043         m_emergethread.setRun(false);
1044         m_thread.stop();
1045         m_emergethread.stop();
1046         
1047         dout_server<<"Server: Threads stopped"<<std::endl;
1048
1049         dout_server<<"Server: Saving players"<<std::endl;
1050         // Save players
1051         // FIXME: Apparently this does not do anything here
1052         //m_env.serializePlayers(m_mapsavedir);
1053 }
1054
1055 void Server::step(float dtime)
1056 {
1057         DSTACK(__FUNCTION_NAME);
1058         // Limit a bit
1059         if(dtime > 2.0)
1060                 dtime = 2.0;
1061         {
1062                 JMutexAutoLock lock(m_step_dtime_mutex);
1063                 m_step_dtime += dtime;
1064         }
1065 }
1066
1067 void Server::AsyncRunStep()
1068 {
1069         DSTACK(__FUNCTION_NAME);
1070         
1071         float dtime;
1072         {
1073                 JMutexAutoLock lock1(m_step_dtime_mutex);
1074                 dtime = m_step_dtime;
1075         }
1076         
1077         // Send blocks to clients
1078         SendBlocks(dtime);
1079         
1080         if(dtime < 0.001)
1081                 return;
1082         
1083         //dstream<<"Server steps "<<dtime<<std::endl;
1084         //dstream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1085         
1086         {
1087                 JMutexAutoLock lock1(m_step_dtime_mutex);
1088                 m_step_dtime -= dtime;
1089         }
1090
1091         /*
1092                 Update uptime
1093         */
1094         {
1095                 m_uptime.set(m_uptime.get() + dtime);
1096         }
1097         
1098         /*
1099                 Update m_time_of_day
1100         */
1101         {
1102                 m_time_counter += dtime;
1103                 f32 speed = g_settings.getFloat("time_speed") * 24000./(24.*3600);
1104                 u32 units = (u32)(m_time_counter*speed);
1105                 m_time_counter -= (f32)units / speed;
1106                 m_time_of_day.set((m_time_of_day.get() + units) % 24000);
1107                 
1108                 //dstream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1109
1110                 /*
1111                         Send to clients at constant intervals
1112                 */
1113
1114                 m_time_of_day_send_timer -= dtime;
1115                 if(m_time_of_day_send_timer < 0.0)
1116                 {
1117                         m_time_of_day_send_timer = g_settings.getFloat("time_send_interval");
1118
1119                         //JMutexAutoLock envlock(m_env_mutex);
1120                         JMutexAutoLock conlock(m_con_mutex);
1121
1122                         for(core::map<u16, RemoteClient*>::Iterator
1123                                 i = m_clients.getIterator();
1124                                 i.atEnd() == false; i++)
1125                         {
1126                                 RemoteClient *client = i.getNode()->getValue();
1127                                 //Player *player = m_env.getPlayer(client->peer_id);
1128                                 
1129                                 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1130                                                 m_time_of_day.get());
1131                                 // Send as reliable
1132                                 m_con.Send(client->peer_id, 0, data, true);
1133                         }
1134                 }
1135         }
1136
1137         {
1138                 // Process connection's timeouts
1139                 JMutexAutoLock lock2(m_con_mutex);
1140                 m_con.RunTimeouts(dtime);
1141         }
1142         
1143         {
1144                 // This has to be called so that the client list gets synced
1145                 // with the peer list of the connection
1146                 handlePeerChanges();
1147         }
1148
1149         {
1150                 // Step environment
1151                 // This also runs Map's timers
1152                 JMutexAutoLock lock(m_env_mutex);
1153                 m_env.step(dtime);
1154         }
1155         
1156         /*
1157                 Do background stuff
1158         */
1159         
1160         /*
1161                 Transform liquids
1162         */
1163         m_liquid_transform_timer += dtime;
1164         if(m_liquid_transform_timer >= 1.00)
1165         {
1166                 m_liquid_transform_timer -= 1.00;
1167                 
1168                 JMutexAutoLock lock(m_env_mutex);
1169                 
1170                 core::map<v3s16, MapBlock*> modified_blocks;
1171                 m_env.getMap().transformLiquids(modified_blocks);
1172 #if 0           
1173                 /*
1174                         Update lighting
1175                 */
1176                 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1177                 ServerMap &map = ((ServerMap&)m_env.getMap());
1178                 map.updateLighting(modified_blocks, lighting_modified_blocks);
1179                 
1180                 // Add blocks modified by lighting to modified_blocks
1181                 for(core::map<v3s16, MapBlock*>::Iterator
1182                                 i = lighting_modified_blocks.getIterator();
1183                                 i.atEnd() == false; i++)
1184                 {
1185                         MapBlock *block = i.getNode()->getValue();
1186                         modified_blocks.insert(block->getPos(), block);
1187                 }
1188 #endif
1189                 /*
1190                         Set the modified blocks unsent for all the clients
1191                 */
1192                 
1193                 JMutexAutoLock lock2(m_con_mutex);
1194
1195                 for(core::map<u16, RemoteClient*>::Iterator
1196                                 i = m_clients.getIterator();
1197                                 i.atEnd() == false; i++)
1198                 {
1199                         RemoteClient *client = i.getNode()->getValue();
1200                         
1201                         if(modified_blocks.size() > 0)
1202                         {
1203                                 // Remove block from sent history
1204                                 client->SetBlocksNotSent(modified_blocks);
1205                         }
1206                 }
1207         }
1208
1209         // Periodically print some info
1210         {
1211                 float &counter = m_print_info_timer;
1212                 counter += dtime;
1213                 if(counter >= 30.0)
1214                 {
1215                         counter = 0.0;
1216
1217                         JMutexAutoLock lock2(m_con_mutex);
1218
1219                         for(core::map<u16, RemoteClient*>::Iterator
1220                                 i = m_clients.getIterator();
1221                                 i.atEnd() == false; i++)
1222                         {
1223                                 //u16 peer_id = i.getNode()->getKey();
1224                                 RemoteClient *client = i.getNode()->getValue();
1225                                 Player *player = m_env.getPlayer(client->peer_id);
1226                                 std::cout<<player->getName()<<"\t";
1227                                 client->PrintInfo(std::cout);
1228                         }
1229                 }
1230         }
1231
1232         //if(g_settings.getBool("enable_experimental"))
1233         {
1234
1235         /*
1236                 Check added and deleted active objects
1237         */
1238         {
1239                 //dstream<<"Server: Checking added and deleted active objects"<<std::endl;
1240
1241                 JMutexAutoLock envlock(m_env_mutex);
1242                 JMutexAutoLock conlock(m_con_mutex);
1243                 
1244                 // Radius inside which objects are active
1245                 s16 radius = 32;
1246
1247                 for(core::map<u16, RemoteClient*>::Iterator
1248                         i = m_clients.getIterator();
1249                         i.atEnd() == false; i++)
1250                 {
1251                         RemoteClient *client = i.getNode()->getValue();
1252                         Player *player = m_env.getPlayer(client->peer_id);
1253                         if(player==NULL)
1254                         {
1255                                 dstream<<"WARNING: "<<__FUNCTION_NAME<<": Client "<<client->peer_id
1256                                                 <<" has no associated player"<<std::endl;
1257                                 continue;
1258                         }
1259                         v3s16 pos = floatToInt(player->getPosition(), BS);
1260
1261                         core::map<u16, bool> removed_objects;
1262                         core::map<u16, bool> added_objects;
1263                         m_env.getRemovedActiveObjects(pos, radius,
1264                                         client->m_known_objects, removed_objects);
1265                         m_env.getAddedActiveObjects(pos, radius,
1266                                         client->m_known_objects, added_objects);
1267                         
1268                         // Ignore if nothing happened
1269                         if(removed_objects.size() == 0 && added_objects.size() == 0)
1270                         {
1271                                 //dstream<<"INFO: active objects: none changed"<<std::endl;
1272                                 continue;
1273                         }
1274                         
1275                         std::string data_buffer;
1276
1277                         char buf[4];
1278                         
1279                         // Handle removed objects
1280                         writeU16((u8*)buf, removed_objects.size());
1281                         data_buffer.append(buf, 2);
1282                         for(core::map<u16, bool>::Iterator
1283                                         i = removed_objects.getIterator();
1284                                         i.atEnd()==false; i++)
1285                         {
1286                                 // Get object
1287                                 u16 id = i.getNode()->getKey();
1288                                 ServerActiveObject* obj = m_env.getActiveObject(id);
1289
1290                                 // Add to data buffer for sending
1291                                 writeU16((u8*)buf, i.getNode()->getKey());
1292                                 data_buffer.append(buf, 2);
1293                                 
1294                                 // Remove from known objects
1295                                 client->m_known_objects.remove(i.getNode()->getKey());
1296
1297                                 if(obj && obj->m_known_by_count > 0)
1298                                         obj->m_known_by_count--;
1299                         }
1300
1301                         // Handle added objects
1302                         writeU16((u8*)buf, added_objects.size());
1303                         data_buffer.append(buf, 2);
1304                         for(core::map<u16, bool>::Iterator
1305                                         i = added_objects.getIterator();
1306                                         i.atEnd()==false; i++)
1307                         {
1308                                 // Get object
1309                                 u16 id = i.getNode()->getKey();
1310                                 ServerActiveObject* obj = m_env.getActiveObject(id);
1311                                 
1312                                 // Get object type
1313                                 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1314                                 if(obj == NULL)
1315                                         dstream<<"WARNING: "<<__FUNCTION_NAME
1316                                                         <<": NULL object"<<std::endl;
1317                                 else
1318                                         type = obj->getType();
1319
1320                                 // Add to data buffer for sending
1321                                 writeU16((u8*)buf, id);
1322                                 data_buffer.append(buf, 2);
1323                                 writeU8((u8*)buf, type);
1324                                 data_buffer.append(buf, 1);
1325
1326                                 data_buffer.append(serializeLongString(
1327                                                 obj->getClientInitializationData()));
1328
1329                                 // Add to known objects
1330                                 client->m_known_objects.insert(i.getNode()->getKey(), false);
1331
1332                                 if(obj)
1333                                         obj->m_known_by_count++;
1334                         }
1335
1336                         // Send packet
1337                         SharedBuffer<u8> reply(2 + data_buffer.size());
1338                         writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1339                         memcpy((char*)&reply[2], data_buffer.c_str(),
1340                                         data_buffer.size());
1341                         // Send as reliable
1342                         m_con.Send(client->peer_id, 0, reply, true);
1343
1344                         dstream<<"INFO: Server: Sent object remove/add: "
1345                                         <<removed_objects.size()<<" removed, "
1346                                         <<added_objects.size()<<" added, "
1347                                         <<"packet size is "<<reply.getSize()<<std::endl;
1348                 }
1349
1350 #if 0
1351                 /*
1352                         Collect a list of all the objects known by the clients
1353                         and report it back to the environment.
1354                 */
1355
1356                 core::map<u16, bool> all_known_objects;
1357
1358                 for(core::map<u16, RemoteClient*>::Iterator
1359                         i = m_clients.getIterator();
1360                         i.atEnd() == false; i++)
1361                 {
1362                         RemoteClient *client = i.getNode()->getValue();
1363                         // Go through all known objects of client
1364                         for(core::map<u16, bool>::Iterator
1365                                         i = client->m_known_objects.getIterator();
1366                                         i.atEnd()==false; i++)
1367                         {
1368                                 u16 id = i.getNode()->getKey();
1369                                 all_known_objects[id] = true;
1370                         }
1371                 }
1372                 
1373                 m_env.setKnownActiveObjects(whatever);
1374 #endif
1375
1376         }
1377
1378         /*
1379                 Send object messages
1380         */
1381         {
1382                 JMutexAutoLock envlock(m_env_mutex);
1383                 JMutexAutoLock conlock(m_con_mutex);
1384
1385                 // Key = object id
1386                 // Value = data sent by object
1387                 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1388
1389                 // Get active object messages from environment
1390                 for(;;)
1391                 {
1392                         ActiveObjectMessage aom = m_env.getActiveObjectMessage();
1393                         if(aom.id == 0)
1394                                 break;
1395                         
1396                         core::list<ActiveObjectMessage>* message_list = NULL;
1397                         core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1398                         n = buffered_messages.find(aom.id);
1399                         if(n == NULL)
1400                         {
1401                                 message_list = new core::list<ActiveObjectMessage>;
1402                                 buffered_messages.insert(aom.id, message_list);
1403                         }
1404                         else
1405                         {
1406                                 message_list = n->getValue();
1407                         }
1408                         message_list->push_back(aom);
1409                 }
1410                 
1411                 // Route data to every client
1412                 for(core::map<u16, RemoteClient*>::Iterator
1413                         i = m_clients.getIterator();
1414                         i.atEnd()==false; i++)
1415                 {
1416                         RemoteClient *client = i.getNode()->getValue();
1417                         std::string reliable_data;
1418                         std::string unreliable_data;
1419                         // Go through all objects in message buffer
1420                         for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1421                                         j = buffered_messages.getIterator();
1422                                         j.atEnd()==false; j++)
1423                         {
1424                                 // If object is not known by client, skip it
1425                                 u16 id = j.getNode()->getKey();
1426                                 if(client->m_known_objects.find(id) == NULL)
1427                                         continue;
1428                                 // Get message list of object
1429                                 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1430                                 // Go through every message
1431                                 for(core::list<ActiveObjectMessage>::Iterator
1432                                                 k = list->begin(); k != list->end(); k++)
1433                                 {
1434                                         // Compose the full new data with header
1435                                         ActiveObjectMessage aom = *k;
1436                                         std::string new_data;
1437                                         // Add object id
1438                                         char buf[2];
1439                                         writeU16((u8*)&buf[0], aom.id);
1440                                         new_data.append(buf, 2);
1441                                         // Add data
1442                                         new_data += serializeString(aom.datastring);
1443                                         // Add data to buffer
1444                                         if(aom.reliable)
1445                                                 reliable_data += new_data;
1446                                         else
1447                                                 unreliable_data += new_data;
1448                                 }
1449                         }
1450                         /*
1451                                 reliable_data and unreliable_data are now ready.
1452                                 Send them.
1453                         */
1454                         if(reliable_data.size() > 0)
1455                         {
1456                                 SharedBuffer<u8> reply(2 + reliable_data.size());
1457                                 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1458                                 memcpy((char*)&reply[2], reliable_data.c_str(),
1459                                                 reliable_data.size());
1460                                 // Send as reliable
1461                                 m_con.Send(client->peer_id, 0, reply, true);
1462                         }
1463                         if(unreliable_data.size() > 0)
1464                         {
1465                                 SharedBuffer<u8> reply(2 + unreliable_data.size());
1466                                 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1467                                 memcpy((char*)&reply[2], unreliable_data.c_str(),
1468                                                 unreliable_data.size());
1469                                 // Send as unreliable
1470                                 m_con.Send(client->peer_id, 0, reply, false);
1471                         }
1472
1473                         /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1474                         {
1475                                 dstream<<"INFO: Server: Size of object message data: "
1476                                                 <<"reliable: "<<reliable_data.size()
1477                                                 <<", unreliable: "<<unreliable_data.size()
1478                                                 <<std::endl;
1479                         }*/
1480                 }
1481
1482                 // Clear buffered_messages
1483                 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1484                                 i = buffered_messages.getIterator();
1485                                 i.atEnd()==false; i++)
1486                 {
1487                         delete i.getNode()->getValue();
1488                 }
1489         }
1490
1491         } // enable_experimental
1492
1493         /*
1494                 Send queued-for-sending map edit events.
1495         */
1496         {
1497                 while(m_unsent_map_edit_queue.size() != 0)
1498                 {
1499                         MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1500
1501                         if(event->type == MEET_ADDNODE)
1502                         {
1503                                 dstream<<"Server: MEET_ADDNODE"<<std::endl;
1504                                 sendAddNode(event->p, event->n, event->already_known_by_peer);
1505                         }
1506                         else if(event->type == MEET_REMOVENODE)
1507                         {
1508                                 dstream<<"Server: MEET_REMOVENODE"<<std::endl;
1509                                 sendRemoveNode(event->p, event->already_known_by_peer);
1510                         }
1511                         else if(event->type == MEET_OTHER)
1512                         {
1513                                 dstream<<"WARNING: Server: MEET_OTHER not implemented"
1514                                                 <<std::endl;
1515                         }
1516                         else
1517                         {
1518                                 dstream<<"WARNING: Server: Unknown MapEditEvent "
1519                                                 <<((u32)event->type)<<std::endl;
1520                         }
1521
1522                         delete event;
1523                 }
1524         }
1525
1526         /*
1527                 Send object positions
1528                 TODO: Get rid of MapBlockObjects
1529         */
1530         {
1531                 float &counter = m_objectdata_timer;
1532                 counter += dtime;
1533                 if(counter >= g_settings.getFloat("objectdata_interval"))
1534                 {
1535                         JMutexAutoLock lock1(m_env_mutex);
1536                         JMutexAutoLock lock2(m_con_mutex);
1537                         SendObjectData(counter);
1538
1539                         counter = 0.0;
1540                 }
1541         }
1542         
1543         /*
1544                 Step node metadata
1545         */
1546         {
1547                 JMutexAutoLock envlock(m_env_mutex);
1548                 JMutexAutoLock conlock(m_con_mutex);
1549                 
1550                 core::map<v3s16, MapBlock*> changed_blocks;
1551                 m_env.getMap().nodeMetadataStep(dtime, changed_blocks);
1552
1553                 for(core::map<v3s16, MapBlock*>::Iterator
1554                                 i = changed_blocks.getIterator();
1555                                 i.atEnd() == false; i++)
1556                 {
1557                         MapBlock *block = i.getNode()->getValue();
1558
1559                         for(core::map<u16, RemoteClient*>::Iterator
1560                                 i = m_clients.getIterator();
1561                                 i.atEnd()==false; i++)
1562                         {
1563                                 RemoteClient *client = i.getNode()->getValue();
1564                                 client->SetBlockNotSent(block->getPos());
1565                         }
1566                 }
1567         }
1568                 
1569         /*
1570                 Trigger emergethread (it somehow gets to a non-triggered but
1571                 bysy state sometimes)
1572         */
1573         {
1574                 float &counter = m_emergethread_trigger_timer;
1575                 counter += dtime;
1576                 if(counter >= 2.0)
1577                 {
1578                         counter = 0.0;
1579                         
1580                         m_emergethread.trigger();
1581                 }
1582         }
1583
1584         // Save map
1585         {
1586                 float &counter = m_savemap_timer;
1587                 counter += dtime;
1588                 if(counter >= g_settings.getFloat("server_map_save_interval"))
1589                 {
1590                         counter = 0.0;
1591
1592                         JMutexAutoLock lock(m_env_mutex);
1593
1594                         if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == true)
1595                         {
1596                                 // Save only changed parts
1597                                 m_env.getMap().save(true);
1598
1599                                 // Delete unused sectors
1600                                 u32 deleted_count = m_env.getMap().deleteUnusedSectors(
1601                                                 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1602                                 if(deleted_count > 0)
1603                                 {
1604                                         dout_server<<"Server: Unloaded "<<deleted_count
1605                                                         <<" sectors from memory"<<std::endl;
1606                                 }
1607
1608                                 // Save players
1609                                 m_env.serializePlayers(m_mapsavedir);
1610                         }
1611                 }
1612         }
1613 }
1614
1615 void Server::Receive()
1616 {
1617         DSTACK(__FUNCTION_NAME);
1618         u32 data_maxsize = 10000;
1619         Buffer<u8> data(data_maxsize);
1620         u16 peer_id;
1621         u32 datasize;
1622         try{
1623                 {
1624                         JMutexAutoLock conlock(m_con_mutex);
1625                         datasize = m_con.Receive(peer_id, *data, data_maxsize);
1626                 }
1627
1628                 // This has to be called so that the client list gets synced
1629                 // with the peer list of the connection
1630                 handlePeerChanges();
1631
1632                 ProcessData(*data, datasize, peer_id);
1633         }
1634         catch(con::InvalidIncomingDataException &e)
1635         {
1636                 derr_server<<"Server::Receive(): "
1637                                 "InvalidIncomingDataException: what()="
1638                                 <<e.what()<<std::endl;
1639         }
1640         catch(con::PeerNotFoundException &e)
1641         {
1642                 //NOTE: This is not needed anymore
1643                 
1644                 // The peer has been disconnected.
1645                 // Find the associated player and remove it.
1646
1647                 /*JMutexAutoLock envlock(m_env_mutex);
1648
1649                 dout_server<<"ServerThread: peer_id="<<peer_id
1650                                 <<" has apparently closed connection. "
1651                                 <<"Removing player."<<std::endl;
1652
1653                 m_env.removePlayer(peer_id);*/
1654         }
1655 }
1656
1657 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1658 {
1659         DSTACK(__FUNCTION_NAME);
1660         // Environment is locked first.
1661         JMutexAutoLock envlock(m_env_mutex);
1662         JMutexAutoLock conlock(m_con_mutex);
1663         
1664         con::Peer *peer;
1665         try{
1666                 peer = m_con.GetPeer(peer_id);
1667         }
1668         catch(con::PeerNotFoundException &e)
1669         {
1670                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1671                                 <<peer_id<<" not found"<<std::endl;
1672                 return;
1673         }
1674         
1675         u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1676
1677         try
1678         {
1679
1680         if(datasize < 2)
1681                 return;
1682
1683         ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1684         
1685         if(command == TOSERVER_INIT)
1686         {
1687                 // [0] u16 TOSERVER_INIT
1688                 // [2] u8 SER_FMT_VER_HIGHEST
1689                 // [3] u8[20] player_name
1690
1691                 if(datasize < 3)
1692                         return;
1693
1694                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1695                                 <<peer->id<<std::endl;
1696
1697                 // First byte after command is maximum supported
1698                 // serialization version
1699                 u8 client_max = data[2];
1700                 u8 our_max = SER_FMT_VER_HIGHEST;
1701                 // Use the highest version supported by both
1702                 u8 deployed = core::min_(client_max, our_max);
1703                 // If it's lower than the lowest supported, give up.
1704                 if(deployed < SER_FMT_VER_LOWEST)
1705                         deployed = SER_FMT_VER_INVALID;
1706
1707                 //peer->serialization_version = deployed;
1708                 getClient(peer->id)->pending_serialization_version = deployed;
1709
1710                 if(deployed == SER_FMT_VER_INVALID)
1711                 {
1712                         derr_server<<DTIME<<"Server: Cannot negotiate "
1713                                         "serialization version with peer "
1714                                         <<peer_id<<std::endl;
1715                         return;
1716                 }
1717
1718                 /*
1719                         Set up player
1720                 */
1721                 
1722                 // Get player name
1723                 const u32 playername_size = 20;
1724                 char playername[playername_size];
1725                 for(u32 i=0; i<playername_size-1; i++)
1726                 {
1727                         playername[i] = data[3+i];
1728                 }
1729                 playername[playername_size-1] = 0;
1730                 
1731                 // Get player
1732                 Player *player = emergePlayer(playername, "", peer_id);
1733                 //Player *player = m_env.getPlayer(peer_id);
1734
1735                 /*{
1736                         // DEBUG: Test serialization
1737                         std::ostringstream test_os;
1738                         player->serialize(test_os);
1739                         dstream<<"Player serialization test: \""<<test_os.str()
1740                                         <<"\""<<std::endl;
1741                         std::istringstream test_is(test_os.str());
1742                         player->deSerialize(test_is);
1743                 }*/
1744
1745                 // If failed, cancel
1746                 if(player == NULL)
1747                 {
1748                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
1749                                         <<": failed to emerge player"<<std::endl;
1750                         return;
1751                 }
1752
1753                 /*
1754                 // If a client is already connected to the player, cancel
1755                 if(player->peer_id != 0)
1756                 {
1757                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
1758                                         <<" tried to connect to "
1759                                         "an already connected player (peer_id="
1760                                         <<player->peer_id<<")"<<std::endl;
1761                         return;
1762                 }
1763                 // Set client of player
1764                 player->peer_id = peer_id;
1765                 */
1766
1767                 // Check if player doesn't exist
1768                 if(player == NULL)
1769                         throw con::InvalidIncomingDataException
1770                                 ("Server::ProcessData(): INIT: Player doesn't exist");
1771
1772                 /*// update name if it was supplied
1773                 if(datasize >= 20+3)
1774                 {
1775                         data[20+3-1] = 0;
1776                         player->updateName((const char*)&data[3]);
1777                 }*/
1778
1779                 // Now answer with a TOCLIENT_INIT
1780                 
1781                 SharedBuffer<u8> reply(2+1+6+8);
1782                 writeU16(&reply[0], TOCLIENT_INIT);
1783                 writeU8(&reply[2], deployed);
1784                 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
1785                 //writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
1786                 
1787                 // Send as reliable
1788                 m_con.Send(peer_id, 0, reply, true);
1789
1790                 return;
1791         }
1792         if(command == TOSERVER_INIT2)
1793         {
1794                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
1795                                 <<peer->id<<std::endl;
1796
1797
1798                 getClient(peer->id)->serialization_version
1799                                 = getClient(peer->id)->pending_serialization_version;
1800
1801                 /*
1802                         Send some initialization data
1803                 */
1804                 
1805                 // Send player info to all players
1806                 SendPlayerInfos();
1807
1808                 // Send inventory to player
1809                 SendInventory(peer->id);
1810                 
1811                 // Send time of day
1812                 {
1813                         SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1814                                         m_time_of_day.get());
1815                         m_con.Send(peer->id, 0, data, true);
1816                 }
1817                 
1818                 // Send information about server to player in chat
1819                 SendChatMessage(peer_id, getStatusString());
1820                 
1821                 // Send information about joining in chat
1822                 {
1823                         std::wstring name = L"unknown";
1824                         Player *player = m_env.getPlayer(peer_id);
1825                         if(player != NULL)
1826                                 name = narrow_to_wide(player->getName());
1827                         
1828                         std::wstring message;
1829                         message += L"*** ";
1830                         message += name;
1831                         message += L" joined game";
1832                         BroadcastChatMessage(message);
1833                 }
1834
1835                 return;
1836         }
1837
1838         if(peer_ser_ver == SER_FMT_VER_INVALID)
1839         {
1840                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
1841                                 " serialization format invalid or not initialized."
1842                                 " Skipping incoming command="<<command<<std::endl;
1843                 return;
1844         }
1845         
1846         Player *player = m_env.getPlayer(peer_id);
1847
1848         if(player == NULL){
1849                 derr_server<<"Server::ProcessData(): Cancelling: "
1850                                 "No player for peer_id="<<peer_id
1851                                 <<std::endl;
1852                 return;
1853         }
1854         if(command == TOSERVER_PLAYERPOS)
1855         {
1856                 if(datasize < 2+12+12+4+4)
1857                         return;
1858         
1859                 u32 start = 0;
1860                 v3s32 ps = readV3S32(&data[start+2]);
1861                 v3s32 ss = readV3S32(&data[start+2+12]);
1862                 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1863                 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1864                 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1865                 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1866                 pitch = wrapDegrees(pitch);
1867                 yaw = wrapDegrees(yaw);
1868                 player->setPosition(position);
1869                 player->setSpeed(speed);
1870                 player->setPitch(pitch);
1871                 player->setYaw(yaw);
1872                 
1873                 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1874                                 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1875                                 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1876         }
1877         else if(command == TOSERVER_GOTBLOCKS)
1878         {
1879                 if(datasize < 2+1)
1880                         return;
1881                 
1882                 /*
1883                         [0] u16 command
1884                         [2] u8 count
1885                         [3] v3s16 pos_0
1886                         [3+6] v3s16 pos_1
1887                         ...
1888                 */
1889
1890                 u16 count = data[2];
1891                 for(u16 i=0; i<count; i++)
1892                 {
1893                         if((s16)datasize < 2+1+(i+1)*6)
1894                                 throw con::InvalidIncomingDataException
1895                                         ("GOTBLOCKS length is too short");
1896                         v3s16 p = readV3S16(&data[2+1+i*6]);
1897                         /*dstream<<"Server: GOTBLOCKS ("
1898                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1899                         RemoteClient *client = getClient(peer_id);
1900                         client->GotBlock(p);
1901                 }
1902         }
1903         else if(command == TOSERVER_DELETEDBLOCKS)
1904         {
1905                 if(datasize < 2+1)
1906                         return;
1907                 
1908                 /*
1909                         [0] u16 command
1910                         [2] u8 count
1911                         [3] v3s16 pos_0
1912                         [3+6] v3s16 pos_1
1913                         ...
1914                 */
1915
1916                 u16 count = data[2];
1917                 for(u16 i=0; i<count; i++)
1918                 {
1919                         if((s16)datasize < 2+1+(i+1)*6)
1920                                 throw con::InvalidIncomingDataException
1921                                         ("DELETEDBLOCKS length is too short");
1922                         v3s16 p = readV3S16(&data[2+1+i*6]);
1923                         /*dstream<<"Server: DELETEDBLOCKS ("
1924                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1925                         RemoteClient *client = getClient(peer_id);
1926                         client->SetBlockNotSent(p);
1927                 }
1928         }
1929         else if(command == TOSERVER_CLICK_OBJECT)
1930         {
1931                 if(datasize < 13)
1932                         return;
1933
1934                 /*
1935                         [0] u16 command
1936                         [2] u8 button (0=left, 1=right)
1937                         [3] v3s16 block
1938                         [9] s16 id
1939                         [11] u16 item
1940                 */
1941                 u8 button = readU8(&data[2]);
1942                 v3s16 p;
1943                 p.X = readS16(&data[3]);
1944                 p.Y = readS16(&data[5]);
1945                 p.Z = readS16(&data[7]);
1946                 s16 id = readS16(&data[9]);
1947                 //u16 item_i = readU16(&data[11]);
1948
1949                 MapBlock *block = NULL;
1950                 try
1951                 {
1952                         block = m_env.getMap().getBlockNoCreate(p);
1953                 }
1954                 catch(InvalidPositionException &e)
1955                 {
1956                         derr_server<<"CLICK_OBJECT block not found"<<std::endl;
1957                         return;
1958                 }
1959
1960                 MapBlockObject *obj = block->getObject(id);
1961
1962                 if(obj == NULL)
1963                 {
1964                         derr_server<<"CLICK_OBJECT object not found"<<std::endl;
1965                         return;
1966                 }
1967
1968                 //TODO: Check that object is reasonably close
1969                 
1970                 // Left click
1971                 if(button == 0)
1972                 {
1973                         InventoryList *ilist = player->inventory.getList("main");
1974                         if(g_settings.getBool("creative_mode") == false && ilist != NULL)
1975                         {
1976                         
1977                                 // Skip if inventory has no free space
1978                                 if(ilist->getUsedSlots() == ilist->getSize())
1979                                 {
1980                                         dout_server<<"Player inventory has no free space"<<std::endl;
1981                                         return;
1982                                 }
1983                                 
1984                                 /*
1985                                         Create the inventory item
1986                                 */
1987                                 InventoryItem *item = NULL;
1988                                 // If it is an item-object, take the item from it
1989                                 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
1990                                 {
1991                                         item = ((ItemObject*)obj)->createInventoryItem();
1992                                 }
1993                                 // Else create an item of the object
1994                                 else
1995                                 {
1996                                         item = new MapBlockObjectItem
1997                                                         (obj->getInventoryString());
1998                                 }
1999                                 
2000                                 // Add to inventory and send inventory
2001                                 ilist->addItem(item);
2002                                 SendInventory(player->peer_id);
2003                         }
2004
2005                         // Remove from block
2006                         block->removeObject(id);
2007                 }
2008         }
2009         else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2010         {
2011                 if(datasize < 7)
2012                         return;
2013
2014                 /*
2015                         length: 7
2016                         [0] u16 command
2017                         [2] u8 button (0=left, 1=right)
2018                         [3] u16 id
2019                         [5] u16 item
2020                 */
2021                 u8 button = readU8(&data[2]);
2022                 u16 id = readS16(&data[3]);
2023                 //u16 item_i = readU16(&data[11]);
2024         
2025                 ServerActiveObject *obj = m_env.getActiveObject(id);
2026
2027                 if(obj == NULL)
2028                 {
2029                         derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2030                                         <<std::endl;
2031                         return;
2032                 }
2033
2034                 //TODO: Check that object is reasonably close
2035                 
2036                 // Left click, pick object up (usually)
2037                 if(button == 0)
2038                 {
2039                         InventoryList *ilist = player->inventory.getList("main");
2040                         if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2041                         {
2042                         
2043                                 // Skip if inventory has no free space
2044                                 if(ilist->getUsedSlots() == ilist->getSize())
2045                                 {
2046                                         dout_server<<"Player inventory has no free space"<<std::endl;
2047                                         return;
2048                                 }
2049
2050                                 // Skip if object has been removed
2051                                 if(obj->m_removed)
2052                                         return;
2053                                 
2054                                 /*
2055                                         Create the inventory item
2056                                 */
2057                                 InventoryItem *item = obj->createPickedUpItem();
2058                                 
2059                                 if(item)
2060                                 {
2061                                         // Add to inventory and send inventory
2062                                         ilist->addItem(item);
2063                                         SendInventory(player->peer_id);
2064
2065                                         // Remove object from environment
2066                                         obj->m_removed = true;
2067                                 }
2068                         }
2069                 }
2070         }
2071         else if(command == TOSERVER_GROUND_ACTION)
2072         {
2073                 if(datasize < 17)
2074                         return;
2075                 /*
2076                         length: 17
2077                         [0] u16 command
2078                         [2] u8 action
2079                         [3] v3s16 nodepos_undersurface
2080                         [9] v3s16 nodepos_abovesurface
2081                         [15] u16 item
2082                         actions:
2083                         0: start digging
2084                         1: place block
2085                         2: stop digging (all parameters ignored)
2086                         3: digging completed
2087                 */
2088                 u8 action = readU8(&data[2]);
2089                 v3s16 p_under;
2090                 p_under.X = readS16(&data[3]);
2091                 p_under.Y = readS16(&data[5]);
2092                 p_under.Z = readS16(&data[7]);
2093                 v3s16 p_over;
2094                 p_over.X = readS16(&data[9]);
2095                 p_over.Y = readS16(&data[11]);
2096                 p_over.Z = readS16(&data[13]);
2097                 u16 item_i = readU16(&data[15]);
2098
2099                 //TODO: Check that target is reasonably close
2100                 
2101                 /*
2102                         0: start digging
2103                 */
2104                 if(action == 0)
2105                 {
2106                         /*
2107                                 NOTE: This can be used in the future to check if
2108                                 somebody is cheating, by checking the timing.
2109                         */
2110                 } // action == 0
2111
2112                 /*
2113                         2: stop digging
2114                 */
2115                 else if(action == 2)
2116                 {
2117 #if 0
2118                         RemoteClient *client = getClient(peer->id);
2119                         JMutexAutoLock digmutex(client->m_dig_mutex);
2120                         client->m_dig_tool_item = -1;
2121 #endif
2122                 }
2123
2124                 /*
2125                         3: Digging completed
2126                 */
2127                 else if(action == 3)
2128                 {
2129                         // Mandatory parameter; actually used for nothing
2130                         core::map<v3s16, MapBlock*> modified_blocks;
2131
2132                         u8 material;
2133                         u8 mineral = MINERAL_NONE;
2134
2135                         bool cannot_remove_node = false;
2136
2137                         try
2138                         {
2139                                 MapNode n = m_env.getMap().getNode(p_under);
2140                                 // Get mineral
2141                                 mineral = n.getMineral();
2142                                 // Get material at position
2143                                 material = n.d;
2144                                 // If not yet cancelled
2145                                 if(cannot_remove_node == false)
2146                                 {
2147                                         // If it's not diggable, do nothing
2148                                         if(content_diggable(material) == false)
2149                                         {
2150                                                 derr_server<<"Server: Not finishing digging: "
2151                                                                 <<"Node not diggable"
2152                                                                 <<std::endl;
2153                                                 cannot_remove_node = true;
2154                                         }
2155                                 }
2156                                 // If not yet cancelled
2157                                 if(cannot_remove_node == false)
2158                                 {
2159                                         // Get node metadata
2160                                         NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2161                                         if(meta && meta->nodeRemovalDisabled() == true)
2162                                         {
2163                                                 derr_server<<"Server: Not finishing digging: "
2164                                                                 <<"Node metadata disables removal"
2165                                                                 <<std::endl;
2166                                                 cannot_remove_node = true;
2167                                         }
2168                                 }
2169                         }
2170                         catch(InvalidPositionException &e)
2171                         {
2172                                 derr_server<<"Server: Not finishing digging: Node not found."
2173                                                 <<" Adding block to emerge queue."
2174                                                 <<std::endl;
2175                                 m_emerge_queue.addBlock(peer_id,
2176                                                 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2177                                 cannot_remove_node = true;
2178                         }
2179
2180                         /*
2181                                 If node can't be removed, set block to be re-sent to
2182                                 client and quit.
2183                         */
2184                         if(cannot_remove_node)
2185                         {
2186                                 derr_server<<"Server: Not finishing digging."<<std::endl;
2187
2188                                 // Client probably has wrong data.
2189                                 // Set block not sent, so that client will get
2190                                 // a valid one.
2191                                 dstream<<"Client "<<peer_id<<" tried to dig "
2192                                                 <<"node; but node cannot be removed."
2193                                                 <<" setting MapBlock not sent."<<std::endl;
2194                                 RemoteClient *client = getClient(peer_id);
2195                                 v3s16 blockpos = getNodeBlockPos(p_under);
2196                                 client->SetBlockNotSent(blockpos);
2197                                         
2198                                 return;
2199                         }
2200                         
2201                         /*
2202                                 Send the removal to all other clients.
2203                                 - If other player is close, send REMOVENODE
2204                                 - Otherwise set blocks not sent
2205                         */
2206                         core::list<u16> far_players;
2207                         sendRemoveNode(p_under, peer_id, &far_players, 100);
2208                         
2209                         /*
2210                                 Update and send inventory
2211                         */
2212
2213                         if(g_settings.getBool("creative_mode") == false)
2214                         {
2215                                 /*
2216                                         Wear out tool
2217                                 */
2218                                 InventoryList *mlist = player->inventory.getList("main");
2219                                 if(mlist != NULL)
2220                                 {
2221                                         InventoryItem *item = mlist->getItem(item_i);
2222                                         if(item && (std::string)item->getName() == "ToolItem")
2223                                         {
2224                                                 ToolItem *titem = (ToolItem*)item;
2225                                                 std::string toolname = titem->getToolName();
2226
2227                                                 // Get digging properties for material and tool
2228                                                 DiggingProperties prop =
2229                                                                 getDiggingProperties(material, toolname);
2230
2231                                                 if(prop.diggable == false)
2232                                                 {
2233                                                         derr_server<<"Server: WARNING: Player digged"
2234                                                                         <<" with impossible material + tool"
2235                                                                         <<" combination"<<std::endl;
2236                                                 }
2237                                                 
2238                                                 bool weared_out = titem->addWear(prop.wear);
2239
2240                                                 if(weared_out)
2241                                                 {
2242                                                         mlist->deleteItem(item_i);
2243                                                 }
2244                                         }
2245                                 }
2246
2247                                 /*
2248                                         Add dug item to inventory
2249                                 */
2250
2251                                 InventoryItem *item = NULL;
2252
2253                                 if(mineral != MINERAL_NONE)
2254                                         item = getDiggedMineralItem(mineral);
2255                                 
2256                                 // If not mineral
2257                                 if(item == NULL)
2258                                 {
2259                                         std::string &dug_s = content_features(material).dug_item;
2260                                         if(dug_s != "")
2261                                         {
2262                                                 std::istringstream is(dug_s, std::ios::binary);
2263                                                 item = InventoryItem::deSerialize(is);
2264                                         }
2265                                 }
2266                                 
2267                                 if(item != NULL)
2268                                 {
2269                                         // Add a item to inventory
2270                                         player->inventory.addItem("main", item);
2271
2272                                         // Send inventory
2273                                         SendInventory(player->peer_id);
2274                                 }
2275                         }
2276
2277                         /*
2278                                 Remove the node
2279                                 (this takes some time so it is done after the quick stuff)
2280                         */
2281                         m_ignore_map_edit_events = true;
2282                         m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2283                         m_ignore_map_edit_events = false;
2284                         
2285                         /*
2286                                 Set blocks not sent to far players
2287                         */
2288                         for(core::list<u16>::Iterator
2289                                         i = far_players.begin();
2290                                         i != far_players.end(); i++)
2291                         {
2292                                 u16 peer_id = *i;
2293                                 RemoteClient *client = getClient(peer_id);
2294                                 if(client==NULL)
2295                                         continue;
2296                                 client->SetBlocksNotSent(modified_blocks);
2297                         }
2298                 }
2299                 
2300                 /*
2301                         1: place block
2302                 */
2303                 else if(action == 1)
2304                 {
2305
2306                         InventoryList *ilist = player->inventory.getList("main");
2307                         if(ilist == NULL)
2308                                 return;
2309
2310                         // Get item
2311                         InventoryItem *item = ilist->getItem(item_i);
2312                         
2313                         // If there is no item, it is not possible to add it anywhere
2314                         if(item == NULL)
2315                                 return;
2316                         
2317                         /*
2318                                 Handle material items
2319                         */
2320                         if(std::string("MaterialItem") == item->getName())
2321                         {
2322                                 try{
2323                                         // Don't add a node if this is not a free space
2324                                         MapNode n2 = m_env.getMap().getNode(p_over);
2325                                         if(content_buildable_to(n2.d) == false)
2326                                         {
2327                                                 // Client probably has wrong data.
2328                                                 // Set block not sent, so that client will get
2329                                                 // a valid one.
2330                                                 dstream<<"Client "<<peer_id<<" tried to place"
2331                                                                 <<" node in invalid position; setting"
2332                                                                 <<" MapBlock not sent."<<std::endl;
2333                                                 RemoteClient *client = getClient(peer_id);
2334                                                 v3s16 blockpos = getNodeBlockPos(p_over);
2335                                                 client->SetBlockNotSent(blockpos);
2336                                                 return;
2337                                         }
2338                                 }
2339                                 catch(InvalidPositionException &e)
2340                                 {
2341                                         derr_server<<"Server: Ignoring ADDNODE: Node not found"
2342                                                         <<" Adding block to emerge queue."
2343                                                         <<std::endl;
2344                                         m_emerge_queue.addBlock(peer_id,
2345                                                         getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2346                                         return;
2347                                 }
2348
2349                                 // Reset build time counter
2350                                 getClient(peer->id)->m_time_from_building = 0.0;
2351                                 
2352                                 // Create node data
2353                                 MaterialItem *mitem = (MaterialItem*)item;
2354                                 MapNode n;
2355                                 n.d = mitem->getMaterial();
2356                                 if(content_features(n.d).wall_mounted)
2357                                         n.dir = packDir(p_under - p_over);
2358                                 
2359                                 /*
2360                                         Send to all players
2361                                 */
2362                                 core::list<u16> far_players;
2363                                 sendAddNode(p_over, n, 0, &far_players, 100);
2364                                 
2365                                 /*
2366                                         Handle inventory
2367                                 */
2368                                 InventoryList *ilist = player->inventory.getList("main");
2369                                 if(g_settings.getBool("creative_mode") == false && ilist)
2370                                 {
2371                                         // Remove from inventory and send inventory
2372                                         if(mitem->getCount() == 1)
2373                                                 ilist->deleteItem(item_i);
2374                                         else
2375                                                 mitem->remove(1);
2376                                         // Send inventory
2377                                         SendInventory(peer_id);
2378                                 }
2379                                 
2380                                 /*
2381                                         Add node.
2382
2383                                         This takes some time so it is done after the quick stuff
2384                                 */
2385                                 core::map<v3s16, MapBlock*> modified_blocks;
2386                                 m_ignore_map_edit_events = true;
2387                                 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2388                                 m_ignore_map_edit_events = false;
2389                                 
2390                                 /*
2391                                         Set blocks not sent to far players
2392                                 */
2393                                 for(core::list<u16>::Iterator
2394                                                 i = far_players.begin();
2395                                                 i != far_players.end(); i++)
2396                                 {
2397                                         u16 peer_id = *i;
2398                                         RemoteClient *client = getClient(peer_id);
2399                                         if(client==NULL)
2400                                                 continue;
2401                                         client->SetBlocksNotSent(modified_blocks);
2402                                 }
2403
2404                                 /*
2405                                         Calculate special events
2406                                 */
2407                                 
2408                                 /*if(n.d == CONTENT_MESE)
2409                                 {
2410                                         u32 count = 0;
2411                                         for(s16 z=-1; z<=1; z++)
2412                                         for(s16 y=-1; y<=1; y++)
2413                                         for(s16 x=-1; x<=1; x++)
2414                                         {
2415                                                 
2416                                         }
2417                                 }*/
2418                         }
2419                         /*
2420                                 Place other item (not a block)
2421                         */
2422                         else
2423                         {
2424                                 v3s16 blockpos = getNodeBlockPos(p_over);
2425                                 
2426                                 /*
2427                                         Check that the block is loaded so that the item
2428                                         can properly be added to the static list too
2429                                 */
2430                                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2431                                 if(block==NULL)
2432                                 {
2433                                         derr_server<<"Error while placing object: "
2434                                                         "block not found"<<std::endl;
2435                                         return;
2436                                 }
2437
2438                                 dout_server<<"Placing a miscellaneous item on map"
2439                                                 <<std::endl;
2440                                 
2441                                 // Calculate a position for it
2442                                 v3f pos = intToFloat(p_over, BS);
2443                                 //pos.Y -= BS*0.45;
2444                                 pos.Y -= BS*0.25; // let it drop a bit
2445                                 // Randomize a bit
2446                                 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2447                                 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2448
2449                                 /*
2450                                         Create the object
2451                                 */
2452                                 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2453
2454                                 if(obj == NULL)
2455                                 {
2456                                         derr_server<<"WARNING: item resulted in NULL object, "
2457                                                         <<"not placing onto map"
2458                                                         <<std::endl;
2459                                 }
2460                                 else
2461                                 {
2462                                         // Add the object to the environment
2463                                         m_env.addActiveObject(obj);
2464                                         
2465                                         dout_server<<"Placed object"<<std::endl;
2466
2467                                         // If item has count<=1, delete it
2468                                         if(item->getCount() <= 1)
2469                                         {
2470                                                 InventoryList *ilist = player->inventory.getList("main");
2471                                                 if(g_settings.getBool("creative_mode") == false && ilist)
2472                                                 {
2473                                                         // Remove from inventory and send inventory
2474                                                         ilist->deleteItem(item_i);
2475                                                         // Send inventory
2476                                                         SendInventory(peer_id);
2477                                                 }
2478                                         }
2479                                         // Else decrement it
2480                                         else
2481                                         {
2482                                                 item->remove(1);
2483                                                 // Send inventory
2484                                                 SendInventory(peer_id);
2485                                         }
2486                                 }
2487                         }
2488
2489                 } // action == 1
2490
2491                 /*
2492                         Catch invalid actions
2493                 */
2494                 else
2495                 {
2496                         derr_server<<"WARNING: Server: Invalid action "
2497                                         <<action<<std::endl;
2498                 }
2499         }
2500 #if 0
2501         else if(command == TOSERVER_RELEASE)
2502         {
2503                 if(datasize < 3)
2504                         return;
2505                 /*
2506                         length: 3
2507                         [0] u16 command
2508                         [2] u8 button
2509                 */
2510                 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
2511         }
2512 #endif
2513         else if(command == TOSERVER_SIGNTEXT)
2514         {
2515                 /*
2516                         u16 command
2517                         v3s16 blockpos
2518                         s16 id
2519                         u16 textlen
2520                         textdata
2521                 */
2522                 std::string datastring((char*)&data[2], datasize-2);
2523                 std::istringstream is(datastring, std::ios_base::binary);
2524                 u8 buf[6];
2525                 // Read stuff
2526                 is.read((char*)buf, 6);
2527                 v3s16 blockpos = readV3S16(buf);
2528                 is.read((char*)buf, 2);
2529                 s16 id = readS16(buf);
2530                 is.read((char*)buf, 2);
2531                 u16 textlen = readU16(buf);
2532                 std::string text;
2533                 for(u16 i=0; i<textlen; i++)
2534                 {
2535                         is.read((char*)buf, 1);
2536                         text += (char)buf[0];
2537                 }
2538
2539                 MapBlock *block = NULL;
2540                 try
2541                 {
2542                         block = m_env.getMap().getBlockNoCreate(blockpos);
2543                 }
2544                 catch(InvalidPositionException &e)
2545                 {
2546                         derr_server<<"Error while setting sign text: "
2547                                         "block not found"<<std::endl;
2548                         return;
2549                 }
2550
2551                 MapBlockObject *obj = block->getObject(id);
2552                 if(obj == NULL)
2553                 {
2554                         derr_server<<"Error while setting sign text: "
2555                                         "object not found"<<std::endl;
2556                         return;
2557                 }
2558                 
2559                 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
2560                 {
2561                         derr_server<<"Error while setting sign text: "
2562                                         "object is not a sign"<<std::endl;
2563                         return;
2564                 }
2565
2566                 ((SignObject*)obj)->setText(text);
2567
2568                 obj->getBlock()->setChangedFlag();
2569         }
2570         else if(command == TOSERVER_SIGNNODETEXT)
2571         {
2572                 /*
2573                         u16 command
2574                         v3s16 p
2575                         u16 textlen
2576                         textdata
2577                 */
2578                 std::string datastring((char*)&data[2], datasize-2);
2579                 std::istringstream is(datastring, std::ios_base::binary);
2580                 u8 buf[6];
2581                 // Read stuff
2582                 is.read((char*)buf, 6);
2583                 v3s16 p = readV3S16(buf);
2584                 is.read((char*)buf, 2);
2585                 u16 textlen = readU16(buf);
2586                 std::string text;
2587                 for(u16 i=0; i<textlen; i++)
2588                 {
2589                         is.read((char*)buf, 1);
2590                         text += (char)buf[0];
2591                 }
2592
2593                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
2594                 if(!meta)
2595                         return;
2596                 if(meta->typeId() != CONTENT_SIGN_WALL)
2597                         return;
2598                 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
2599                 signmeta->setText(text);
2600                 
2601                 v3s16 blockpos = getNodeBlockPos(p);
2602                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2603                 if(block)
2604                 {
2605                         block->setChangedFlag();
2606                 }
2607
2608                 for(core::map<u16, RemoteClient*>::Iterator
2609                         i = m_clients.getIterator();
2610                         i.atEnd()==false; i++)
2611                 {
2612                         RemoteClient *client = i.getNode()->getValue();
2613                         client->SetBlockNotSent(blockpos);
2614                 }
2615         }
2616         else if(command == TOSERVER_INVENTORY_ACTION)
2617         {
2618                 /*// Ignore inventory changes if in creative mode
2619                 if(g_settings.getBool("creative_mode") == true)
2620                 {
2621                         dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
2622                                         <<std::endl;
2623                         return;
2624                 }*/
2625                 // Strip command and create a stream
2626                 std::string datastring((char*)&data[2], datasize-2);
2627                 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2628                 std::istringstream is(datastring, std::ios_base::binary);
2629                 // Create an action
2630                 InventoryAction *a = InventoryAction::deSerialize(is);
2631                 if(a != NULL)
2632                 {
2633                         // Create context
2634                         InventoryContext c;
2635                         c.current_player = player;
2636
2637                         /*
2638                                 Handle craftresult specially if not in creative mode
2639                         */
2640                         bool disable_action = false;
2641                         if(a->getType() == IACTION_MOVE
2642                                         && g_settings.getBool("creative_mode") == false)
2643                         {
2644                                 IMoveAction *ma = (IMoveAction*)a;
2645                                 if(ma->to_inv == "current_player" &&
2646                                                 ma->from_inv == "current_player")
2647                                 {
2648                                         // Don't allow moving anything to craftresult
2649                                         if(ma->to_list == "craftresult")
2650                                         {
2651                                                 // Do nothing
2652                                                 disable_action = true;
2653                                         }
2654                                         // When something is removed from craftresult
2655                                         if(ma->from_list == "craftresult")
2656                                         {
2657                                                 disable_action = true;
2658                                                 // Remove stuff from craft
2659                                                 InventoryList *clist = player->inventory.getList("craft");
2660                                                 if(clist)
2661                                                 {
2662                                                         u16 count = ma->count;
2663                                                         if(count == 0)
2664                                                                 count = 1;
2665                                                         clist->decrementMaterials(count);
2666                                                 }
2667                                                 // Do action
2668                                                 // Feed action to player inventory
2669                                                 //a->apply(&player->inventory);
2670                                                 a->apply(&c, this);
2671                                                 // Eat it
2672                                                 delete a;
2673                                                 // If something appeared in craftresult, throw it
2674                                                 // in the main list
2675                                                 InventoryList *rlist = player->inventory.getList("craftresult");
2676                                                 InventoryList *mlist = player->inventory.getList("main");
2677                                                 if(rlist && mlist && rlist->getUsedSlots() == 1)
2678                                                 {
2679                                                         InventoryItem *item1 = rlist->changeItem(0, NULL);
2680                                                         mlist->addItem(item1);
2681                                                 }
2682                                         }
2683                                 }
2684                         }
2685                         
2686                         if(disable_action == false)
2687                         {
2688                                 // Feed action to player inventory
2689                                 //a->apply(&player->inventory);
2690                                 a->apply(&c, this);
2691                                 // Eat the action
2692                                 delete a;
2693                         }
2694                         else
2695                         {
2696                                 // Send inventory
2697                                 SendInventory(player->peer_id);
2698                         }
2699                 }
2700                 else
2701                 {
2702                         dstream<<"TOSERVER_INVENTORY_ACTION: "
2703                                         <<"InventoryAction::deSerialize() returned NULL"
2704                                         <<std::endl;
2705                 }
2706         }
2707         else if(command == TOSERVER_CHAT_MESSAGE)
2708         {
2709                 /*
2710                         u16 command
2711                         u16 length
2712                         wstring message
2713                 */
2714                 u8 buf[6];
2715                 std::string datastring((char*)&data[2], datasize-2);
2716                 std::istringstream is(datastring, std::ios_base::binary);
2717                 
2718                 // Read stuff
2719                 is.read((char*)buf, 2);
2720                 u16 len = readU16(buf);
2721                 
2722                 std::wstring message;
2723                 for(u16 i=0; i<len; i++)
2724                 {
2725                         is.read((char*)buf, 2);
2726                         message += (wchar_t)readU16(buf);
2727                 }
2728
2729                 // Get player name of this client
2730                 std::wstring name = narrow_to_wide(player->getName());
2731                 
2732                 // Line to send to players
2733                 std::wstring line;
2734                 // Whether to send to the player that sent the line
2735                 bool send_to_sender = false;
2736                 // Whether to send to other players
2737                 bool send_to_others = false;
2738                 
2739                 // Parse commands
2740                 std::wstring commandprefix = L"/#";
2741                 if(message.substr(0, commandprefix.size()) == commandprefix)
2742                 {
2743                         line += L"Server: ";
2744
2745                         message = message.substr(commandprefix.size());
2746                         // Get player name as narrow string
2747                         std::string name_s = player->getName();
2748                         // Convert message to narrow string
2749                         std::string message_s = wide_to_narrow(message);
2750                         // Operator is the single name defined in config.
2751                         std::string operator_name = g_settings.get("name");
2752                         bool is_operator = (operator_name != "" &&
2753                                         wide_to_narrow(name) == operator_name);
2754                         bool valid_command = false;
2755                         if(message_s == "help")
2756                         {
2757                                 line += L"-!- Available commands: ";
2758                                 line += L"status ";
2759                                 if(is_operator)
2760                                 {
2761                                         line += L"shutdown setting ";
2762                                 }
2763                                 else
2764                                 {
2765                                 }
2766                                 send_to_sender = true;
2767                                 valid_command = true;
2768                         }
2769                         else if(message_s == "status")
2770                         {
2771                                 line = getStatusString();
2772                                 send_to_sender = true;
2773                                 valid_command = true;
2774                         }
2775                         else if(is_operator)
2776                         {
2777                                 if(message_s == "shutdown")
2778                                 {
2779                                         dstream<<DTIME<<" Server: Operator requested shutdown."
2780                                                         <<std::endl;
2781                                         m_shutdown_requested.set(true);
2782                                         
2783                                         line += L"*** Server shutting down (operator request)";
2784                                         send_to_sender = true;
2785                                         valid_command = true;
2786                                 }
2787                                 else if(message_s.substr(0,8) == "setting ")
2788                                 {
2789                                         std::string confline = message_s.substr(8);
2790                                         g_settings.parseConfigLine(confline);
2791                                         line += L"-!- Setting changed.";
2792                                         send_to_sender = true;
2793                                         valid_command = true;
2794                                 }
2795                         }
2796                         
2797                         if(valid_command == false)
2798                         {
2799                                 line += L"-!- Invalid command: " + message;
2800                                 send_to_sender = true;
2801                         }
2802                 }
2803                 else
2804                 {
2805                         line += L"<";
2806                         /*if(is_operator)
2807                                 line += L"@";*/
2808                         line += name;
2809                         line += L"> ";
2810                         line += message;
2811                         send_to_others = true;
2812                 }
2813                 
2814                 if(line != L"")
2815                 {
2816                         dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2817
2818                         /*
2819                                 Send the message to clients
2820                         */
2821                         for(core::map<u16, RemoteClient*>::Iterator
2822                                 i = m_clients.getIterator();
2823                                 i.atEnd() == false; i++)
2824                         {
2825                                 // Get client and check that it is valid
2826                                 RemoteClient *client = i.getNode()->getValue();
2827                                 assert(client->peer_id == i.getNode()->getKey());
2828                                 if(client->serialization_version == SER_FMT_VER_INVALID)
2829                                         continue;
2830
2831                                 // Filter recipient
2832                                 bool sender_selected = (peer_id == client->peer_id);
2833                                 if(sender_selected == true && send_to_sender == false)
2834                                         continue;
2835                                 if(sender_selected == false && send_to_others == false)
2836                                         continue;
2837
2838                                 SendChatMessage(client->peer_id, line);
2839                         }
2840                 }
2841         }
2842         else
2843         {
2844                 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
2845                                 "unknown command "<<command<<std::endl;
2846         }
2847         
2848         } //try
2849         catch(SendFailedException &e)
2850         {
2851                 derr_server<<"Server::ProcessData(): SendFailedException: "
2852                                 <<"what="<<e.what()
2853                                 <<std::endl;
2854         }
2855 }
2856
2857 void Server::onMapEditEvent(MapEditEvent *event)
2858 {
2859         dstream<<"Server::onMapEditEvent()"<<std::endl;
2860         if(m_ignore_map_edit_events)
2861                 return;
2862         MapEditEvent *e = event->clone();
2863         m_unsent_map_edit_queue.push_back(e);
2864 }
2865
2866 Inventory* Server::getInventory(InventoryContext *c, std::string id)
2867 {
2868         if(id == "current_player")
2869         {
2870                 assert(c->current_player);
2871                 return &(c->current_player->inventory);
2872         }
2873         
2874         Strfnd fn(id);
2875         std::string id0 = fn.next(":");
2876
2877         if(id0 == "nodemeta")
2878         {
2879                 v3s16 p;
2880                 p.X = stoi(fn.next(","));
2881                 p.Y = stoi(fn.next(","));
2882                 p.Z = stoi(fn.next(","));
2883                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
2884                 if(meta)
2885                         return meta->getInventory();
2886                 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
2887                                 <<"no metadata found"<<std::endl;
2888                 return NULL;
2889         }
2890
2891         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
2892         return NULL;
2893 }
2894 void Server::inventoryModified(InventoryContext *c, std::string id)
2895 {
2896         if(id == "current_player")
2897         {
2898                 assert(c->current_player);
2899                 // Send inventory
2900                 SendInventory(c->current_player->peer_id);
2901                 return;
2902         }
2903         
2904         Strfnd fn(id);
2905         std::string id0 = fn.next(":");
2906
2907         if(id0 == "nodemeta")
2908         {
2909                 v3s16 p;
2910                 p.X = stoi(fn.next(","));
2911                 p.Y = stoi(fn.next(","));
2912                 p.Z = stoi(fn.next(","));
2913                 v3s16 blockpos = getNodeBlockPos(p);
2914
2915                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
2916                 if(meta)
2917                         meta->inventoryModified();
2918
2919                 for(core::map<u16, RemoteClient*>::Iterator
2920                         i = m_clients.getIterator();
2921                         i.atEnd()==false; i++)
2922                 {
2923                         RemoteClient *client = i.getNode()->getValue();
2924                         client->SetBlockNotSent(blockpos);
2925                 }
2926
2927                 return;
2928         }
2929
2930         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
2931 }
2932
2933 core::list<PlayerInfo> Server::getPlayerInfo()
2934 {
2935         DSTACK(__FUNCTION_NAME);
2936         JMutexAutoLock envlock(m_env_mutex);
2937         JMutexAutoLock conlock(m_con_mutex);
2938         
2939         core::list<PlayerInfo> list;
2940
2941         core::list<Player*> players = m_env.getPlayers();
2942         
2943         core::list<Player*>::Iterator i;
2944         for(i = players.begin();
2945                         i != players.end(); i++)
2946         {
2947                 PlayerInfo info;
2948
2949                 Player *player = *i;
2950
2951                 try{
2952                         con::Peer *peer = m_con.GetPeer(player->peer_id);
2953                         // Copy info from peer to info struct
2954                         info.id = peer->id;
2955                         info.address = peer->address;
2956                         info.avg_rtt = peer->avg_rtt;
2957                 }
2958                 catch(con::PeerNotFoundException &e)
2959                 {
2960                         // Set dummy peer info
2961                         info.id = 0;
2962                         info.address = Address(0,0,0,0,0);
2963                         info.avg_rtt = 0.0;
2964                 }
2965
2966                 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
2967                 info.position = player->getPosition();
2968
2969                 list.push_back(info);
2970         }
2971
2972         return list;
2973 }
2974
2975
2976 void Server::peerAdded(con::Peer *peer)
2977 {
2978         DSTACK(__FUNCTION_NAME);
2979         dout_server<<"Server::peerAdded(): peer->id="
2980                         <<peer->id<<std::endl;
2981         
2982         PeerChange c;
2983         c.type = PEER_ADDED;
2984         c.peer_id = peer->id;
2985         c.timeout = false;
2986         m_peer_change_queue.push_back(c);
2987 }
2988
2989 void Server::deletingPeer(con::Peer *peer, bool timeout)
2990 {
2991         DSTACK(__FUNCTION_NAME);
2992         dout_server<<"Server::deletingPeer(): peer->id="
2993                         <<peer->id<<", timeout="<<timeout<<std::endl;
2994         
2995         PeerChange c;
2996         c.type = PEER_REMOVED;
2997         c.peer_id = peer->id;
2998         c.timeout = timeout;
2999         m_peer_change_queue.push_back(c);
3000 }
3001
3002 void Server::SendObjectData(float dtime)
3003 {
3004         DSTACK(__FUNCTION_NAME);
3005
3006         core::map<v3s16, bool> stepped_blocks;
3007         
3008         for(core::map<u16, RemoteClient*>::Iterator
3009                 i = m_clients.getIterator();
3010                 i.atEnd() == false; i++)
3011         {
3012                 u16 peer_id = i.getNode()->getKey();
3013                 RemoteClient *client = i.getNode()->getValue();
3014                 assert(client->peer_id == peer_id);
3015                 
3016                 if(client->serialization_version == SER_FMT_VER_INVALID)
3017                         continue;
3018                 
3019                 client->SendObjectData(this, dtime, stepped_blocks);
3020         }
3021 }
3022
3023 void Server::SendPlayerInfos()
3024 {
3025         DSTACK(__FUNCTION_NAME);
3026
3027         //JMutexAutoLock envlock(m_env_mutex);
3028         
3029         // Get connected players
3030         core::list<Player*> players = m_env.getPlayers(true);
3031         
3032         u32 player_count = players.getSize();
3033         u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3034
3035         SharedBuffer<u8> data(datasize);
3036         writeU16(&data[0], TOCLIENT_PLAYERINFO);
3037         
3038         u32 start = 2;
3039         core::list<Player*>::Iterator i;
3040         for(i = players.begin();
3041                         i != players.end(); i++)
3042         {
3043                 Player *player = *i;
3044
3045                 /*dstream<<"Server sending player info for player with "
3046                                 "peer_id="<<player->peer_id<<std::endl;*/
3047                 
3048                 writeU16(&data[start], player->peer_id);
3049                 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3050                 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3051                 start += 2+PLAYERNAME_SIZE;
3052         }
3053
3054         //JMutexAutoLock conlock(m_con_mutex);
3055
3056         // Send as reliable
3057         m_con.SendToAll(0, data, true);
3058 }
3059
3060 void Server::SendInventory(u16 peer_id)
3061 {
3062         DSTACK(__FUNCTION_NAME);
3063         
3064         Player* player = m_env.getPlayer(peer_id);
3065
3066         /*
3067                 Calculate crafting stuff
3068         */
3069         if(g_settings.getBool("creative_mode") == false)
3070         {
3071                 InventoryList *clist = player->inventory.getList("craft");
3072                 InventoryList *rlist = player->inventory.getList("craftresult");
3073                 if(rlist)
3074                 {
3075                         rlist->clearItems();
3076                 }
3077                 if(clist && rlist)
3078                 {
3079                         InventoryItem *items[9];
3080                         for(u16 i=0; i<9; i++)
3081                         {
3082                                 items[i] = clist->getItem(i);
3083                         }
3084                         
3085                         bool found = false;
3086
3087                         // Wood
3088                         if(!found)
3089                         {
3090                                 ItemSpec specs[9];
3091                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_TREE);
3092                                 if(checkItemCombination(items, specs))
3093                                 {
3094                                         rlist->addItem(new MaterialItem(CONTENT_WOOD, 4));
3095                                         found = true;
3096                                 }
3097                         }
3098
3099                         // Stick
3100                         if(!found)
3101                         {
3102                                 ItemSpec specs[9];
3103                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3104                                 if(checkItemCombination(items, specs))
3105                                 {
3106                                         rlist->addItem(new CraftItem("Stick", 4));
3107                                         found = true;
3108                                 }
3109                         }
3110
3111                         // Sign
3112                         if(!found)
3113                         {
3114                                 ItemSpec specs[9];
3115                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3116                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3117                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3118                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3119                                 specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3120                                 specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3121                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3122                                 if(checkItemCombination(items, specs))
3123                                 {
3124                                         //rlist->addItem(new MapBlockObjectItem("Sign"));
3125                                         rlist->addItem(new MaterialItem(CONTENT_SIGN_WALL, 1));
3126                                         found = true;
3127                                 }
3128                         }
3129
3130                         // Torch
3131                         if(!found)
3132                         {
3133                                 ItemSpec specs[9];
3134                                 specs[0] = ItemSpec(ITEM_CRAFT, "lump_of_coal");
3135                                 specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
3136                                 if(checkItemCombination(items, specs))
3137                                 {
3138                                         rlist->addItem(new MaterialItem(CONTENT_TORCH, 4));
3139                                         found = true;
3140                                 }
3141                         }
3142
3143                         // Wooden pick
3144                         if(!found)
3145                         {
3146                                 ItemSpec specs[9];
3147                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3148                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3149                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3150                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3151                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3152                                 if(checkItemCombination(items, specs))
3153                                 {
3154                                         rlist->addItem(new ToolItem("WPick", 0));
3155                                         found = true;
3156                                 }
3157                         }
3158
3159                         // Stone pick
3160                         if(!found)
3161                         {
3162                                 ItemSpec specs[9];
3163                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3164                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3165                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3166                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3167                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3168                                 if(checkItemCombination(items, specs))
3169                                 {
3170                                         rlist->addItem(new ToolItem("STPick", 0));
3171                                         found = true;
3172                                 }
3173                         }
3174
3175                         // Steel pick
3176                         if(!found)
3177                         {
3178                                 ItemSpec specs[9];
3179                                 specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3180                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3181                                 specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3182                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3183                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3184                                 if(checkItemCombination(items, specs))
3185                                 {
3186                                         rlist->addItem(new ToolItem("SteelPick", 0));
3187                                         found = true;
3188                                 }
3189                         }
3190
3191                         // Mese pick
3192                         if(!found)
3193                         {
3194                                 ItemSpec specs[9];
3195                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
3196                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
3197                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
3198                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3199                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3200                                 if(checkItemCombination(items, specs))
3201                                 {
3202                                         rlist->addItem(new ToolItem("MesePick", 0));
3203                                         found = true;
3204                                 }
3205                         }
3206
3207                         // Wooden showel
3208                         if(!found)
3209                         {
3210                                 ItemSpec specs[9];
3211                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3212                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3213                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3214                                 if(checkItemCombination(items, specs))
3215                                 {
3216                                         rlist->addItem(new ToolItem("WShovel", 0));
3217                                         found = true;
3218                                 }
3219                         }
3220
3221                         // Stone showel
3222                         if(!found)
3223                         {
3224                                 ItemSpec specs[9];
3225                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3226                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3227                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3228                                 if(checkItemCombination(items, specs))
3229                                 {
3230                                         rlist->addItem(new ToolItem("STShovel", 0));
3231                                         found = true;
3232                                 }
3233                         }
3234
3235                         // Steel showel
3236                         if(!found)
3237                         {
3238                                 ItemSpec specs[9];
3239                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3240                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3241                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3242                                 if(checkItemCombination(items, specs))
3243                                 {
3244                                         rlist->addItem(new ToolItem("SteelShovel", 0));
3245                                         found = true;
3246                                 }
3247                         }
3248
3249                         // Wooden axe
3250                         if(!found)
3251                         {
3252                                 ItemSpec specs[9];
3253                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3254                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3255                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3256                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3257                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3258                                 if(checkItemCombination(items, specs))
3259                                 {
3260                                         rlist->addItem(new ToolItem("WAxe", 0));
3261                                         found = true;
3262                                 }
3263                         }
3264
3265                         // Stone axe
3266                         if(!found)
3267                         {
3268                                 ItemSpec specs[9];
3269                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3270                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3271                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3272                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3273                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3274                                 if(checkItemCombination(items, specs))
3275                                 {
3276                                         rlist->addItem(new ToolItem("STAxe", 0));
3277                                         found = true;
3278                                 }
3279                         }
3280
3281                         // Steel axe
3282                         if(!found)
3283                         {
3284                                 ItemSpec specs[9];
3285                                 specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3286                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3287                                 specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3288                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3289                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3290                                 if(checkItemCombination(items, specs))
3291                                 {
3292                                         rlist->addItem(new ToolItem("SteelAxe", 0));
3293                                         found = true;
3294                                 }
3295                         }
3296
3297                         // Chest
3298                         if(!found)
3299                         {
3300                                 ItemSpec specs[9];
3301                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3302                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3303                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3304                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3305                                 specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3306                                 specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3307                                 specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3308                                 specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3309                                 if(checkItemCombination(items, specs))
3310                                 {
3311                                         rlist->addItem(new MaterialItem(CONTENT_CHEST, 1));
3312                                         found = true;
3313                                 }
3314                         }
3315
3316                         // Furnace
3317                         if(!found)
3318                         {
3319                                 ItemSpec specs[9];
3320                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3321                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3322                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3323                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3324                                 specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3325                                 specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3326                                 specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3327                                 specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3328                                 if(checkItemCombination(items, specs))
3329                                 {
3330                                         rlist->addItem(new MaterialItem(CONTENT_FURNACE, 1));
3331                                         found = true;
3332                                 }
3333                         }
3334
3335                         // Steel block
3336                         if(!found)
3337                         {
3338                                 ItemSpec specs[9];
3339                                 specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3340                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3341                                 specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3342                                 specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3343                                 specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3344                                 specs[5] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3345                                 specs[6] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3346                                 specs[7] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3347                                 specs[8] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3348                                 if(checkItemCombination(items, specs))
3349                                 {
3350                                         rlist->addItem(new MaterialItem(CONTENT_STEEL, 1));
3351                                         found = true;
3352                                 }
3353                         }
3354
3355                 }
3356         } // if creative_mode == false
3357
3358         /*
3359                 Serialize it
3360         */
3361
3362         std::ostringstream os;
3363         //os.imbue(std::locale("C"));
3364
3365         player->inventory.serialize(os);
3366
3367         std::string s = os.str();
3368         
3369         SharedBuffer<u8> data(s.size()+2);
3370         writeU16(&data[0], TOCLIENT_INVENTORY);
3371         memcpy(&data[2], s.c_str(), s.size());
3372         
3373         // Send as reliable
3374         m_con.Send(peer_id, 0, data, true);
3375 }
3376
3377 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3378 {
3379         DSTACK(__FUNCTION_NAME);
3380         
3381         std::ostringstream os(std::ios_base::binary);
3382         u8 buf[12];
3383         
3384         // Write command
3385         writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3386         os.write((char*)buf, 2);
3387         
3388         // Write length
3389         writeU16(buf, message.size());
3390         os.write((char*)buf, 2);
3391         
3392         // Write string
3393         for(u32 i=0; i<message.size(); i++)
3394         {
3395                 u16 w = message[i];
3396                 writeU16(buf, w);
3397                 os.write((char*)buf, 2);
3398         }
3399         
3400         // Make data buffer
3401         std::string s = os.str();
3402         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3403         // Send as reliable
3404         m_con.Send(peer_id, 0, data, true);
3405 }
3406
3407 void Server::BroadcastChatMessage(const std::wstring &message)
3408 {
3409         for(core::map<u16, RemoteClient*>::Iterator
3410                 i = m_clients.getIterator();
3411                 i.atEnd() == false; i++)
3412         {
3413                 // Get client and check that it is valid
3414                 RemoteClient *client = i.getNode()->getValue();
3415                 assert(client->peer_id == i.getNode()->getKey());
3416                 if(client->serialization_version == SER_FMT_VER_INVALID)
3417                         continue;
3418
3419                 SendChatMessage(client->peer_id, message);
3420         }
3421 }
3422
3423 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3424         core::list<u16> *far_players, float far_d_nodes)
3425 {
3426         float maxd = far_d_nodes*BS;
3427         v3f p_f = intToFloat(p, BS);
3428
3429         // Create packet
3430         u32 replysize = 8;
3431         SharedBuffer<u8> reply(replysize);
3432         writeU16(&reply[0], TOCLIENT_REMOVENODE);
3433         writeS16(&reply[2], p.X);
3434         writeS16(&reply[4], p.Y);
3435         writeS16(&reply[6], p.Z);
3436
3437         for(core::map<u16, RemoteClient*>::Iterator
3438                 i = m_clients.getIterator();
3439                 i.atEnd() == false; i++)
3440         {
3441                 // Get client and check that it is valid
3442                 RemoteClient *client = i.getNode()->getValue();
3443                 assert(client->peer_id == i.getNode()->getKey());
3444                 if(client->serialization_version == SER_FMT_VER_INVALID)
3445                         continue;
3446
3447                 // Don't send if it's the same one
3448                 if(client->peer_id == ignore_id)
3449                         continue;
3450                 
3451                 if(far_players)
3452                 {
3453                         // Get player
3454                         Player *player = m_env.getPlayer(client->peer_id);
3455                         if(player)
3456                         {
3457                                 // If player is far away, only set modified blocks not sent
3458                                 v3f player_pos = player->getPosition();
3459                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3460                                 {
3461                                         far_players->push_back(client->peer_id);
3462                                         continue;
3463                                 }
3464                         }
3465                 }
3466
3467                 // Send as reliable
3468                 m_con.Send(client->peer_id, 0, reply, true);
3469         }
3470 }
3471
3472 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3473                 core::list<u16> *far_players, float far_d_nodes)
3474 {
3475         float maxd = far_d_nodes*BS;
3476         v3f p_f = intToFloat(p, BS);
3477
3478         for(core::map<u16, RemoteClient*>::Iterator
3479                 i = m_clients.getIterator();
3480                 i.atEnd() == false; i++)
3481         {
3482                 // Get client and check that it is valid
3483                 RemoteClient *client = i.getNode()->getValue();
3484                 assert(client->peer_id == i.getNode()->getKey());
3485                 if(client->serialization_version == SER_FMT_VER_INVALID)
3486                         continue;
3487
3488                 // Don't send if it's the same one
3489                 if(client->peer_id == ignore_id)
3490                         continue;
3491
3492                 if(far_players)
3493                 {
3494                         // Get player
3495                         Player *player = m_env.getPlayer(client->peer_id);
3496                         if(player)
3497                         {
3498                                 // If player is far away, only set modified blocks not sent
3499                                 v3f player_pos = player->getPosition();
3500                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3501                                 {
3502                                         far_players->push_back(client->peer_id);
3503                                         continue;
3504                                 }
3505                         }
3506                 }
3507
3508                 // Create packet
3509                 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3510                 SharedBuffer<u8> reply(replysize);
3511                 writeU16(&reply[0], TOCLIENT_ADDNODE);
3512                 writeS16(&reply[2], p.X);
3513                 writeS16(&reply[4], p.Y);
3514                 writeS16(&reply[6], p.Z);
3515                 n.serialize(&reply[8], client->serialization_version);
3516
3517                 // Send as reliable
3518                 m_con.Send(client->peer_id, 0, reply, true);
3519         }
3520 }
3521
3522 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3523 {
3524         DSTACK(__FUNCTION_NAME);
3525         /*
3526                 Create a packet with the block in the right format
3527         */
3528         
3529         std::ostringstream os(std::ios_base::binary);
3530         block->serialize(os, ver);
3531         std::string s = os.str();
3532         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3533
3534         u32 replysize = 8 + blockdata.getSize();
3535         SharedBuffer<u8> reply(replysize);
3536         v3s16 p = block->getPos();
3537         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3538         writeS16(&reply[2], p.X);
3539         writeS16(&reply[4], p.Y);
3540         writeS16(&reply[6], p.Z);
3541         memcpy(&reply[8], *blockdata, blockdata.getSize());
3542
3543         /*dstream<<"Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3544                         <<":  \tpacket size: "<<replysize<<std::endl;*/
3545         
3546         /*
3547                 Send packet
3548         */
3549         m_con.Send(peer_id, 1, reply, true);
3550 }
3551
3552 void Server::SendBlocks(float dtime)
3553 {
3554         DSTACK(__FUNCTION_NAME);
3555
3556         JMutexAutoLock envlock(m_env_mutex);
3557         JMutexAutoLock conlock(m_con_mutex);
3558
3559         //TimeTaker timer("Server::SendBlocks");
3560
3561         core::array<PrioritySortedBlockTransfer> queue;
3562
3563         s32 total_sending = 0;
3564
3565         for(core::map<u16, RemoteClient*>::Iterator
3566                 i = m_clients.getIterator();
3567                 i.atEnd() == false; i++)
3568         {
3569                 RemoteClient *client = i.getNode()->getValue();
3570                 assert(client->peer_id == i.getNode()->getKey());
3571
3572                 total_sending += client->SendingCount();
3573                 
3574                 if(client->serialization_version == SER_FMT_VER_INVALID)
3575                         continue;
3576                 
3577                 client->GetNextBlocks(this, dtime, queue);
3578         }
3579
3580         // Sort.
3581         // Lowest priority number comes first.
3582         // Lowest is most important.
3583         queue.sort();
3584
3585         for(u32 i=0; i<queue.size(); i++)
3586         {
3587                 //TODO: Calculate limit dynamically
3588                 if(total_sending >= g_settings.getS32
3589                                 ("max_simultaneous_block_sends_server_total"))
3590                         break;
3591                 
3592                 PrioritySortedBlockTransfer q = queue[i];
3593
3594                 MapBlock *block = NULL;
3595                 try
3596                 {
3597                         block = m_env.getMap().getBlockNoCreate(q.pos);
3598                 }
3599                 catch(InvalidPositionException &e)
3600                 {
3601                         continue;
3602                 }
3603
3604                 RemoteClient *client = getClient(q.peer_id);
3605
3606                 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3607
3608                 client->SentBlock(q.pos);
3609
3610                 total_sending++;
3611         }
3612 }
3613
3614
3615 RemoteClient* Server::getClient(u16 peer_id)
3616 {
3617         DSTACK(__FUNCTION_NAME);
3618         //JMutexAutoLock lock(m_con_mutex);
3619         core::map<u16, RemoteClient*>::Node *n;
3620         n = m_clients.find(peer_id);
3621         // A client should exist for all peers
3622         assert(n != NULL);
3623         return n->getValue();
3624 }
3625
3626 std::wstring Server::getStatusString()
3627 {
3628         std::wostringstream os(std::ios_base::binary);
3629         os<<L"# Server: ";
3630         // Uptime
3631         os<<L"uptime="<<m_uptime.get();
3632         // Information about clients
3633         os<<L", clients={";
3634         for(core::map<u16, RemoteClient*>::Iterator
3635                 i = m_clients.getIterator();
3636                 i.atEnd() == false; i++)
3637         {
3638                 // Get client and check that it is valid
3639                 RemoteClient *client = i.getNode()->getValue();
3640                 assert(client->peer_id == i.getNode()->getKey());
3641                 if(client->serialization_version == SER_FMT_VER_INVALID)
3642                         continue;
3643                 // Get player
3644                 Player *player = m_env.getPlayer(client->peer_id);
3645                 // Get name of player
3646                 std::wstring name = L"unknown";
3647                 if(player != NULL)
3648                         name = narrow_to_wide(player->getName());
3649                 // Add name to information string
3650                 os<<name<<L",";
3651         }
3652         os<<L"}";
3653         if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
3654                 os<<" WARNING: Map saving is disabled."<<std::endl;
3655         return os.str();
3656 }
3657
3658
3659 void setCreativeInventory(Player *player)
3660 {
3661         player->resetInventory();
3662         
3663         // Give some good picks
3664         {
3665                 InventoryItem *item = new ToolItem("STPick", 0);
3666                 void* r = player->inventory.addItem("main", item);
3667                 assert(r == NULL);
3668         }
3669         {
3670                 InventoryItem *item = new ToolItem("MesePick", 0);
3671                 void* r = player->inventory.addItem("main", item);
3672                 assert(r == NULL);
3673         }
3674
3675         /*
3676                 Give materials
3677         */
3678         
3679         // CONTENT_IGNORE-terminated list
3680         u8 material_items[] = {
3681                 CONTENT_TORCH,
3682                 CONTENT_COBBLE,
3683                 CONTENT_MUD,
3684                 CONTENT_STONE,
3685                 CONTENT_SAND,
3686                 CONTENT_TREE,
3687                 CONTENT_LEAVES,
3688                 CONTENT_MESE,
3689                 CONTENT_WATERSOURCE,
3690                 CONTENT_CLOUD,
3691                 CONTENT_CHEST,
3692                 CONTENT_FURNACE,
3693                 CONTENT_SIGN_WALL,
3694                 CONTENT_IGNORE
3695         };
3696         
3697         u8 *mip = material_items;
3698         for(u16 i=0; i<PLAYER_INVENTORY_SIZE; i++)
3699         {
3700                 if(*mip == CONTENT_IGNORE)
3701                         break;
3702
3703                 InventoryItem *item = new MaterialItem(*mip, 1);
3704                 player->inventory.addItem("main", item);
3705
3706                 mip++;
3707         }
3708
3709 #if 0
3710         assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
3711         
3712         // add torch first
3713         InventoryItem *item = new MaterialItem(CONTENT_TORCH, 1);
3714         player->inventory.addItem("main", item);
3715         
3716         // Then others
3717         for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
3718         {
3719                 // Skip some materials
3720                 if(i == CONTENT_WATER || i == CONTENT_TORCH
3721                         || i == CONTENT_COALSTONE)
3722                         continue;
3723
3724                 InventoryItem *item = new MaterialItem(i, 1);
3725                 player->inventory.addItem("main", item);
3726         }
3727 #endif
3728
3729         /*// Sign
3730         {
3731                 InventoryItem *item = new MapBlockObjectItem("Sign Example text");
3732                 void* r = player->inventory.addItem("main", item);
3733                 assert(r == NULL);
3734         }*/
3735 }
3736
3737 Player *Server::emergePlayer(const char *name, const char *password,
3738                 u16 peer_id)
3739 {
3740         /*
3741                 Try to get an existing player
3742         */
3743         Player *player = m_env.getPlayer(name);
3744         if(player != NULL)
3745         {
3746                 // If player is already connected, cancel
3747                 if(player->peer_id != 0)
3748                 {
3749                         dstream<<"emergePlayer(): Player already connected"<<std::endl;
3750                         return NULL;
3751                 }
3752
3753                 // Got one.
3754                 player->peer_id = peer_id;
3755                 
3756                 // Reset inventory to creative if in creative mode
3757                 if(g_settings.getBool("creative_mode"))
3758                 {
3759                         setCreativeInventory(player);
3760                 }
3761
3762                 return player;
3763         }
3764
3765         /*
3766                 If player with the wanted peer_id already exists, cancel.
3767         */
3768         if(m_env.getPlayer(peer_id) != NULL)
3769         {
3770                 dstream<<"emergePlayer(): Player with wrong name but same"
3771                                 " peer_id already exists"<<std::endl;
3772                 return NULL;
3773         }
3774         
3775         /*
3776                 Create a new player
3777         */
3778         {
3779                 player = new ServerRemotePlayer();
3780                 //player->peer_id = c.peer_id;
3781                 //player->peer_id = PEER_ID_INEXISTENT;
3782                 player->peer_id = peer_id;
3783                 player->updateName(name);
3784
3785                 /*
3786                         Set player position
3787                 */
3788                 
3789                 dstream<<"Server: Finding spawn place for player \""
3790                                 <<player->getName()<<"\""<<std::endl;
3791
3792                 v2s16 nodepos;
3793 #if 0
3794                 player->setPosition(intToFloat(v3s16(
3795                                 0,
3796                                 45, //64,
3797                                 0
3798                 ), BS));
3799 #endif
3800 #if 1
3801                 s16 groundheight = 0;
3802 #if 1
3803                 // Try to find a good place a few times
3804                 for(s32 i=0; i<1000; i++)
3805                 {
3806                         s32 range = 1 + i;
3807                         // We're going to try to throw the player to this position
3808                         nodepos = v2s16(-range + (myrand()%(range*2)),
3809                                         -range + (myrand()%(range*2)));
3810                         v2s16 sectorpos = getNodeSectorPos(nodepos);
3811                         // Get sector (NOTE: Don't get because it's slow)
3812                         //m_env.getMap().emergeSector(sectorpos);
3813                         // Get ground height at point (fallbacks to heightmap function)
3814                         groundheight = m_env.getServerMap().findGroundLevel(nodepos);
3815                         // Don't go underwater
3816                         if(groundheight < WATER_LEVEL)
3817                         {
3818                                 //dstream<<"-> Underwater"<<std::endl;
3819                                 continue;
3820                         }
3821                         // Don't go to high places
3822                         if(groundheight > WATER_LEVEL + 4)
3823                         {
3824                                 //dstream<<"-> Underwater"<<std::endl;
3825                                 continue;
3826                         }
3827
3828                         // Found a good place
3829                         dstream<<"Searched through "<<i<<" places."<<std::endl;
3830                         break;
3831                 }
3832 #endif
3833                 
3834                 // If no suitable place was not found, go above water at least.
3835                 if(groundheight < WATER_LEVEL)
3836                         groundheight = WATER_LEVEL;
3837
3838                 player->setPosition(intToFloat(v3s16(
3839                                 nodepos.X,
3840                                 groundheight + 5, // Accomodate mud
3841                                 nodepos.Y
3842                 ), BS));
3843 #endif
3844
3845                 /*
3846                         Add player to environment
3847                 */
3848
3849                 m_env.addPlayer(player);
3850
3851                 /*
3852                         Add stuff to inventory
3853                 */
3854                 
3855                 if(g_settings.getBool("creative_mode"))
3856                 {
3857                         setCreativeInventory(player);
3858                 }
3859                 else
3860                 {
3861                         /*{
3862                                 InventoryItem *item = new ToolItem("WPick", 32000);
3863                                 void* r = player->inventory.addItem("main", item);
3864                                 assert(r == NULL);
3865                         }*/
3866                         /*{
3867                                 InventoryItem *item = new MaterialItem(CONTENT_MESE, 6);
3868                                 void* r = player->inventory.addItem("main", item);
3869                                 assert(r == NULL);
3870                         }
3871                         {
3872                                 InventoryItem *item = new MaterialItem(CONTENT_COALSTONE, 6);
3873                                 void* r = player->inventory.addItem("main", item);
3874                                 assert(r == NULL);
3875                         }
3876                         {
3877                                 InventoryItem *item = new MaterialItem(CONTENT_WOOD, 6);
3878                                 void* r = player->inventory.addItem("main", item);
3879                                 assert(r == NULL);
3880                         }
3881                         {
3882                                 InventoryItem *item = new CraftItem("Stick", 4);
3883                                 void* r = player->inventory.addItem("main", item);
3884                                 assert(r == NULL);
3885                         }
3886                         {
3887                                 InventoryItem *item = new ToolItem("WPick", 32000);
3888                                 void* r = player->inventory.addItem("main", item);
3889                                 assert(r == NULL);
3890                         }
3891                         {
3892                                 InventoryItem *item = new ToolItem("STPick", 32000);
3893                                 void* r = player->inventory.addItem("main", item);
3894                                 assert(r == NULL);
3895                         }*/
3896                         /*// Give some lights
3897                         {
3898                                 InventoryItem *item = new MaterialItem(CONTENT_TORCH, 999);
3899                                 bool r = player->inventory.addItem("main", item);
3900                                 assert(r == true);
3901                         }
3902                         // and some signs
3903                         for(u16 i=0; i<4; i++)
3904                         {
3905                                 InventoryItem *item = new MapBlockObjectItem("Sign Example text");
3906                                 bool r = player->inventory.addItem("main", item);
3907                                 assert(r == true);
3908                         }*/
3909                         /*// Give some other stuff
3910                         {
3911                                 InventoryItem *item = new MaterialItem(CONTENT_TREE, 999);
3912                                 bool r = player->inventory.addItem("main", item);
3913                                 assert(r == true);
3914                         }*/
3915                 }
3916
3917                 return player;
3918                 
3919         } // create new player
3920 }
3921
3922 void Server::handlePeerChange(PeerChange &c)
3923 {
3924         JMutexAutoLock envlock(m_env_mutex);
3925         JMutexAutoLock conlock(m_con_mutex);
3926         
3927         if(c.type == PEER_ADDED)
3928         {
3929                 /*
3930                         Add
3931                 */
3932
3933                 // Error check
3934                 core::map<u16, RemoteClient*>::Node *n;
3935                 n = m_clients.find(c.peer_id);
3936                 // The client shouldn't already exist
3937                 assert(n == NULL);
3938
3939                 // Create client
3940                 RemoteClient *client = new RemoteClient();
3941                 client->peer_id = c.peer_id;
3942                 m_clients.insert(client->peer_id, client);
3943
3944         } // PEER_ADDED
3945         else if(c.type == PEER_REMOVED)
3946         {
3947                 /*
3948                         Delete
3949                 */
3950
3951                 // Error check
3952                 core::map<u16, RemoteClient*>::Node *n;
3953                 n = m_clients.find(c.peer_id);
3954                 // The client should exist
3955                 assert(n != NULL);
3956                 
3957                 // Collect information about leaving in chat
3958                 std::wstring message;
3959                 {
3960                         std::wstring name = L"unknown";
3961                         Player *player = m_env.getPlayer(c.peer_id);
3962                         if(player != NULL)
3963                                 name = narrow_to_wide(player->getName());
3964                         
3965                         message += L"*** ";
3966                         message += name;
3967                         message += L" left game";
3968                         if(c.timeout)
3969                                 message += L" (timed out)";
3970                 }
3971
3972                 /*// Delete player
3973                 {
3974                         m_env.removePlayer(c.peer_id);
3975                 }*/
3976
3977                 // Set player client disconnected
3978                 {
3979                         Player *player = m_env.getPlayer(c.peer_id);
3980                         if(player != NULL)
3981                                 player->peer_id = 0;
3982                 }
3983                 
3984                 // Delete client
3985                 delete m_clients[c.peer_id];
3986                 m_clients.remove(c.peer_id);
3987
3988                 // Send player info to all remaining clients
3989                 SendPlayerInfos();
3990                 
3991                 // Send leave chat message to all remaining clients
3992                 BroadcastChatMessage(message);
3993                 
3994         } // PEER_REMOVED
3995         else
3996         {
3997                 assert(0);
3998         }
3999 }
4000
4001 void Server::handlePeerChanges()
4002 {
4003         while(m_peer_change_queue.size() > 0)
4004         {
4005                 PeerChange c = m_peer_change_queue.pop_front();
4006
4007                 dout_server<<"Server: Handling peer change: "
4008                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4009                                 <<std::endl;
4010
4011                 handlePeerChange(c);
4012         }
4013 }
4014
4015 void dedicated_server_loop(Server &server, bool &kill)
4016 {
4017         DSTACK(__FUNCTION_NAME);
4018         
4019         std::cout<<DTIME<<std::endl;
4020         std::cout<<"========================"<<std::endl;
4021         std::cout<<"Running dedicated server"<<std::endl;
4022         std::cout<<"========================"<<std::endl;
4023         std::cout<<std::endl;
4024
4025         for(;;)
4026         {
4027                 // This is kind of a hack but can be done like this
4028                 // because server.step() is very light
4029                 sleep_ms(30);
4030                 server.step(0.030);
4031
4032                 if(server.getShutdownRequested() || kill)
4033                 {
4034                         std::cout<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4035                         break;
4036                 }
4037
4038                 static int counter = 0;
4039                 counter--;
4040                 if(counter <= 0)
4041                 {
4042                         counter = 10;
4043
4044                         core::list<PlayerInfo> list = server.getPlayerInfo();
4045                         core::list<PlayerInfo>::Iterator i;
4046                         static u32 sum_old = 0;
4047                         u32 sum = PIChecksum(list);
4048                         if(sum != sum_old)
4049                         {
4050                                 std::cout<<DTIME<<"Player info:"<<std::endl;
4051                                 for(i=list.begin(); i!=list.end(); i++)
4052                                 {
4053                                         i->PrintLine(&std::cout);
4054                                 }
4055                         }
4056                         sum_old = sum;
4057                 }
4058         }
4059 }
4060
4061