]> git.lizzy.rs Git - minetest.git/blob - src/server.cpp
fixing
[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         avg_rtt = 0;
896 }
897
898 void PlayerInfo::PrintLine(std::ostream *s)
899 {
900         (*s)<<id<<": ";
901         (*s)<<"\""<<name<<"\" ("
902                         <<(position.X/10)<<","<<(position.Y/10)
903                         <<","<<(position.Z/10)<<") ";
904         address.print(s);
905         (*s)<<" avg_rtt="<<avg_rtt;
906         (*s)<<std::endl;
907 }
908
909 u32 PIChecksum(core::list<PlayerInfo> &l)
910 {
911         core::list<PlayerInfo>::Iterator i;
912         u32 checksum = 1;
913         u32 a = 10;
914         for(i=l.begin(); i!=l.end(); i++)
915         {
916                 checksum += a * (i->id+1);
917                 checksum ^= 0x435aafcd;
918                 a *= 10;
919         }
920         return checksum;
921 }
922
923 /*
924         Server
925 */
926
927 Server::Server(
928                 std::string mapsavedir
929         ):
930         m_env(new ServerMap(mapsavedir), this),
931         m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
932         m_thread(this),
933         m_emergethread(this),
934         m_time_of_day(9000),
935         m_time_counter(0),
936         m_time_of_day_send_timer(0),
937         m_uptime(0),
938         m_mapsavedir(mapsavedir),
939         m_shutdown_requested(false),
940         m_ignore_map_edit_events(false),
941         m_ignore_map_edit_events_peer_id(0)
942 {
943         m_liquid_transform_timer = 0.0;
944         m_print_info_timer = 0.0;
945         m_objectdata_timer = 0.0;
946         m_emergethread_trigger_timer = 0.0;
947         m_savemap_timer = 0.0;
948         
949         m_env_mutex.Init();
950         m_con_mutex.Init();
951         m_step_dtime_mutex.Init();
952         m_step_dtime = 0.0;
953
954         m_env.getMap().addEventReceiver(this);
955
956         // Load players
957         m_env.deSerializePlayers(m_mapsavedir);
958 }
959
960 Server::~Server()
961 {
962         /*
963                 Send shutdown message
964         */
965         {
966                 JMutexAutoLock conlock(m_con_mutex);
967                 
968                 std::wstring line = L"*** Server shutting down";
969
970                 /*
971                         Send the message to clients
972                 */
973                 for(core::map<u16, RemoteClient*>::Iterator
974                         i = m_clients.getIterator();
975                         i.atEnd() == false; i++)
976                 {
977                         // Get client and check that it is valid
978                         RemoteClient *client = i.getNode()->getValue();
979                         assert(client->peer_id == i.getNode()->getKey());
980                         if(client->serialization_version == SER_FMT_VER_INVALID)
981                                 continue;
982
983                         SendChatMessage(client->peer_id, line);
984                 }
985         }
986
987         /*
988                 Save players
989         */
990         m_env.serializePlayers(m_mapsavedir);
991         
992         /*
993                 Stop threads
994         */
995         stop();
996         
997         /*
998                 Delete clients
999         */
1000         {
1001                 JMutexAutoLock clientslock(m_con_mutex);
1002
1003                 for(core::map<u16, RemoteClient*>::Iterator
1004                         i = m_clients.getIterator();
1005                         i.atEnd() == false; i++)
1006                 {
1007                         /*// Delete player
1008                         // NOTE: These are removed by env destructor
1009                         {
1010                                 u16 peer_id = i.getNode()->getKey();
1011                                 JMutexAutoLock envlock(m_env_mutex);
1012                                 m_env.removePlayer(peer_id);
1013                         }*/
1014                         
1015                         // Delete client
1016                         delete i.getNode()->getValue();
1017                 }
1018         }
1019 }
1020
1021 void Server::start(unsigned short port)
1022 {
1023         DSTACK(__FUNCTION_NAME);
1024         // Stop thread if already running
1025         m_thread.stop();
1026         
1027         // Initialize connection
1028         m_con.setTimeoutMs(30);
1029         m_con.Serve(port);
1030
1031         // Start thread
1032         m_thread.setRun(true);
1033         m_thread.Start();
1034         
1035         dout_server<<"Server: Started on port "<<port<<std::endl;
1036 }
1037
1038 void Server::stop()
1039 {
1040         DSTACK(__FUNCTION_NAME);
1041
1042         // Stop threads (set run=false first so both start stopping)
1043         m_thread.setRun(false);
1044         m_emergethread.setRun(false);
1045         m_thread.stop();
1046         m_emergethread.stop();
1047         
1048         dout_server<<"Server: Threads stopped"<<std::endl;
1049
1050         dout_server<<"Server: Saving players"<<std::endl;
1051         // Save players
1052         // FIXME: Apparently this does not do anything here
1053         //m_env.serializePlayers(m_mapsavedir);
1054 }
1055
1056 void Server::step(float dtime)
1057 {
1058         DSTACK(__FUNCTION_NAME);
1059         // Limit a bit
1060         if(dtime > 2.0)
1061                 dtime = 2.0;
1062         {
1063                 JMutexAutoLock lock(m_step_dtime_mutex);
1064                 m_step_dtime += dtime;
1065         }
1066 }
1067
1068 void Server::AsyncRunStep()
1069 {
1070         DSTACK(__FUNCTION_NAME);
1071         
1072         float dtime;
1073         {
1074                 JMutexAutoLock lock1(m_step_dtime_mutex);
1075                 dtime = m_step_dtime;
1076         }
1077         
1078         // Send blocks to clients
1079         SendBlocks(dtime);
1080         
1081         if(dtime < 0.001)
1082                 return;
1083         
1084         //dstream<<"Server steps "<<dtime<<std::endl;
1085         //dstream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1086         
1087         {
1088                 JMutexAutoLock lock1(m_step_dtime_mutex);
1089                 m_step_dtime -= dtime;
1090         }
1091
1092         /*
1093                 Update uptime
1094         */
1095         {
1096                 m_uptime.set(m_uptime.get() + dtime);
1097         }
1098         
1099         /*
1100                 Update m_time_of_day
1101         */
1102         {
1103                 m_time_counter += dtime;
1104                 f32 speed = g_settings.getFloat("time_speed") * 24000./(24.*3600);
1105                 u32 units = (u32)(m_time_counter*speed);
1106                 m_time_counter -= (f32)units / speed;
1107                 m_time_of_day.set((m_time_of_day.get() + units) % 24000);
1108                 
1109                 //dstream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1110
1111                 /*
1112                         Send to clients at constant intervals
1113                 */
1114
1115                 m_time_of_day_send_timer -= dtime;
1116                 if(m_time_of_day_send_timer < 0.0)
1117                 {
1118                         m_time_of_day_send_timer = g_settings.getFloat("time_send_interval");
1119
1120                         //JMutexAutoLock envlock(m_env_mutex);
1121                         JMutexAutoLock conlock(m_con_mutex);
1122
1123                         for(core::map<u16, RemoteClient*>::Iterator
1124                                 i = m_clients.getIterator();
1125                                 i.atEnd() == false; i++)
1126                         {
1127                                 RemoteClient *client = i.getNode()->getValue();
1128                                 //Player *player = m_env.getPlayer(client->peer_id);
1129                                 
1130                                 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1131                                                 m_time_of_day.get());
1132                                 // Send as reliable
1133                                 m_con.Send(client->peer_id, 0, data, true);
1134                         }
1135                 }
1136         }
1137
1138         {
1139                 // Process connection's timeouts
1140                 JMutexAutoLock lock2(m_con_mutex);
1141                 m_con.RunTimeouts(dtime);
1142         }
1143         
1144         {
1145                 // This has to be called so that the client list gets synced
1146                 // with the peer list of the connection
1147                 handlePeerChanges();
1148         }
1149
1150         {
1151                 // Step environment
1152                 // This also runs Map's timers
1153                 JMutexAutoLock lock(m_env_mutex);
1154                 m_env.step(dtime);
1155         }
1156         
1157         /*
1158                 Do background stuff
1159         */
1160         
1161         /*
1162                 Transform liquids
1163         */
1164         m_liquid_transform_timer += dtime;
1165         if(m_liquid_transform_timer >= 1.00)
1166         {
1167                 m_liquid_transform_timer -= 1.00;
1168                 
1169                 JMutexAutoLock lock(m_env_mutex);
1170                 
1171                 core::map<v3s16, MapBlock*> modified_blocks;
1172                 m_env.getMap().transformLiquids(modified_blocks);
1173 #if 0           
1174                 /*
1175                         Update lighting
1176                 */
1177                 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1178                 ServerMap &map = ((ServerMap&)m_env.getMap());
1179                 map.updateLighting(modified_blocks, lighting_modified_blocks);
1180                 
1181                 // Add blocks modified by lighting to modified_blocks
1182                 for(core::map<v3s16, MapBlock*>::Iterator
1183                                 i = lighting_modified_blocks.getIterator();
1184                                 i.atEnd() == false; i++)
1185                 {
1186                         MapBlock *block = i.getNode()->getValue();
1187                         modified_blocks.insert(block->getPos(), block);
1188                 }
1189 #endif
1190                 /*
1191                         Set the modified blocks unsent for all the clients
1192                 */
1193                 
1194                 JMutexAutoLock lock2(m_con_mutex);
1195
1196                 for(core::map<u16, RemoteClient*>::Iterator
1197                                 i = m_clients.getIterator();
1198                                 i.atEnd() == false; i++)
1199                 {
1200                         RemoteClient *client = i.getNode()->getValue();
1201                         
1202                         if(modified_blocks.size() > 0)
1203                         {
1204                                 // Remove block from sent history
1205                                 client->SetBlocksNotSent(modified_blocks);
1206                         }
1207                 }
1208         }
1209
1210         // Periodically print some info
1211         {
1212                 float &counter = m_print_info_timer;
1213                 counter += dtime;
1214                 if(counter >= 30.0)
1215                 {
1216                         counter = 0.0;
1217
1218                         JMutexAutoLock lock2(m_con_mutex);
1219
1220                         for(core::map<u16, RemoteClient*>::Iterator
1221                                 i = m_clients.getIterator();
1222                                 i.atEnd() == false; i++)
1223                         {
1224                                 //u16 peer_id = i.getNode()->getKey();
1225                                 RemoteClient *client = i.getNode()->getValue();
1226                                 Player *player = m_env.getPlayer(client->peer_id);
1227                                 if(player==NULL)
1228                                         continue;
1229                                 std::cout<<player->getName()<<"\t";
1230                                 client->PrintInfo(std::cout);
1231                         }
1232                 }
1233         }
1234
1235         //if(g_settings.getBool("enable_experimental"))
1236         {
1237
1238         /*
1239                 Check added and deleted active objects
1240         */
1241         {
1242                 //dstream<<"Server: Checking added and deleted active objects"<<std::endl;
1243
1244                 JMutexAutoLock envlock(m_env_mutex);
1245                 JMutexAutoLock conlock(m_con_mutex);
1246                 
1247                 // Radius inside which objects are active
1248                 s16 radius = 32;
1249
1250                 for(core::map<u16, RemoteClient*>::Iterator
1251                         i = m_clients.getIterator();
1252                         i.atEnd() == false; i++)
1253                 {
1254                         RemoteClient *client = i.getNode()->getValue();
1255                         Player *player = m_env.getPlayer(client->peer_id);
1256                         if(player==NULL)
1257                         {
1258                                 dstream<<"WARNING: "<<__FUNCTION_NAME<<": Client "<<client->peer_id
1259                                                 <<" has no associated player"<<std::endl;
1260                                 continue;
1261                         }
1262                         v3s16 pos = floatToInt(player->getPosition(), BS);
1263
1264                         core::map<u16, bool> removed_objects;
1265                         core::map<u16, bool> added_objects;
1266                         m_env.getRemovedActiveObjects(pos, radius,
1267                                         client->m_known_objects, removed_objects);
1268                         m_env.getAddedActiveObjects(pos, radius,
1269                                         client->m_known_objects, added_objects);
1270                         
1271                         // Ignore if nothing happened
1272                         if(removed_objects.size() == 0 && added_objects.size() == 0)
1273                         {
1274                                 //dstream<<"INFO: active objects: none changed"<<std::endl;
1275                                 continue;
1276                         }
1277                         
1278                         std::string data_buffer;
1279
1280                         char buf[4];
1281                         
1282                         // Handle removed objects
1283                         writeU16((u8*)buf, removed_objects.size());
1284                         data_buffer.append(buf, 2);
1285                         for(core::map<u16, bool>::Iterator
1286                                         i = removed_objects.getIterator();
1287                                         i.atEnd()==false; i++)
1288                         {
1289                                 // Get object
1290                                 u16 id = i.getNode()->getKey();
1291                                 ServerActiveObject* obj = m_env.getActiveObject(id);
1292
1293                                 // Add to data buffer for sending
1294                                 writeU16((u8*)buf, i.getNode()->getKey());
1295                                 data_buffer.append(buf, 2);
1296                                 
1297                                 // Remove from known objects
1298                                 client->m_known_objects.remove(i.getNode()->getKey());
1299
1300                                 if(obj && obj->m_known_by_count > 0)
1301                                         obj->m_known_by_count--;
1302                         }
1303
1304                         // Handle added objects
1305                         writeU16((u8*)buf, added_objects.size());
1306                         data_buffer.append(buf, 2);
1307                         for(core::map<u16, bool>::Iterator
1308                                         i = added_objects.getIterator();
1309                                         i.atEnd()==false; i++)
1310                         {
1311                                 // Get object
1312                                 u16 id = i.getNode()->getKey();
1313                                 ServerActiveObject* obj = m_env.getActiveObject(id);
1314                                 
1315                                 // Get object type
1316                                 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1317                                 if(obj == NULL)
1318                                         dstream<<"WARNING: "<<__FUNCTION_NAME
1319                                                         <<": NULL object"<<std::endl;
1320                                 else
1321                                         type = obj->getType();
1322
1323                                 // Add to data buffer for sending
1324                                 writeU16((u8*)buf, id);
1325                                 data_buffer.append(buf, 2);
1326                                 writeU8((u8*)buf, type);
1327                                 data_buffer.append(buf, 1);
1328                                 
1329                                 if(obj)
1330                                         data_buffer.append(serializeLongString(
1331                                                         obj->getClientInitializationData()));
1332                                 else
1333                                         data_buffer.append(serializeLongString(""));
1334
1335                                 // Add to known objects
1336                                 client->m_known_objects.insert(i.getNode()->getKey(), false);
1337
1338                                 if(obj)
1339                                         obj->m_known_by_count++;
1340                         }
1341
1342                         // Send packet
1343                         SharedBuffer<u8> reply(2 + data_buffer.size());
1344                         writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1345                         memcpy((char*)&reply[2], data_buffer.c_str(),
1346                                         data_buffer.size());
1347                         // Send as reliable
1348                         m_con.Send(client->peer_id, 0, reply, true);
1349
1350                         dstream<<"INFO: Server: Sent object remove/add: "
1351                                         <<removed_objects.size()<<" removed, "
1352                                         <<added_objects.size()<<" added, "
1353                                         <<"packet size is "<<reply.getSize()<<std::endl;
1354                 }
1355
1356 #if 0
1357                 /*
1358                         Collect a list of all the objects known by the clients
1359                         and report it back to the environment.
1360                 */
1361
1362                 core::map<u16, bool> all_known_objects;
1363
1364                 for(core::map<u16, RemoteClient*>::Iterator
1365                         i = m_clients.getIterator();
1366                         i.atEnd() == false; i++)
1367                 {
1368                         RemoteClient *client = i.getNode()->getValue();
1369                         // Go through all known objects of client
1370                         for(core::map<u16, bool>::Iterator
1371                                         i = client->m_known_objects.getIterator();
1372                                         i.atEnd()==false; i++)
1373                         {
1374                                 u16 id = i.getNode()->getKey();
1375                                 all_known_objects[id] = true;
1376                         }
1377                 }
1378                 
1379                 m_env.setKnownActiveObjects(whatever);
1380 #endif
1381
1382         }
1383
1384         /*
1385                 Send object messages
1386         */
1387         {
1388                 JMutexAutoLock envlock(m_env_mutex);
1389                 JMutexAutoLock conlock(m_con_mutex);
1390
1391                 // Key = object id
1392                 // Value = data sent by object
1393                 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1394
1395                 // Get active object messages from environment
1396                 for(;;)
1397                 {
1398                         ActiveObjectMessage aom = m_env.getActiveObjectMessage();
1399                         if(aom.id == 0)
1400                                 break;
1401                         
1402                         core::list<ActiveObjectMessage>* message_list = NULL;
1403                         core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1404                         n = buffered_messages.find(aom.id);
1405                         if(n == NULL)
1406                         {
1407                                 message_list = new core::list<ActiveObjectMessage>;
1408                                 buffered_messages.insert(aom.id, message_list);
1409                         }
1410                         else
1411                         {
1412                                 message_list = n->getValue();
1413                         }
1414                         message_list->push_back(aom);
1415                 }
1416                 
1417                 // Route data to every client
1418                 for(core::map<u16, RemoteClient*>::Iterator
1419                         i = m_clients.getIterator();
1420                         i.atEnd()==false; i++)
1421                 {
1422                         RemoteClient *client = i.getNode()->getValue();
1423                         std::string reliable_data;
1424                         std::string unreliable_data;
1425                         // Go through all objects in message buffer
1426                         for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1427                                         j = buffered_messages.getIterator();
1428                                         j.atEnd()==false; j++)
1429                         {
1430                                 // If object is not known by client, skip it
1431                                 u16 id = j.getNode()->getKey();
1432                                 if(client->m_known_objects.find(id) == NULL)
1433                                         continue;
1434                                 // Get message list of object
1435                                 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1436                                 // Go through every message
1437                                 for(core::list<ActiveObjectMessage>::Iterator
1438                                                 k = list->begin(); k != list->end(); k++)
1439                                 {
1440                                         // Compose the full new data with header
1441                                         ActiveObjectMessage aom = *k;
1442                                         std::string new_data;
1443                                         // Add object id
1444                                         char buf[2];
1445                                         writeU16((u8*)&buf[0], aom.id);
1446                                         new_data.append(buf, 2);
1447                                         // Add data
1448                                         new_data += serializeString(aom.datastring);
1449                                         // Add data to buffer
1450                                         if(aom.reliable)
1451                                                 reliable_data += new_data;
1452                                         else
1453                                                 unreliable_data += new_data;
1454                                 }
1455                         }
1456                         /*
1457                                 reliable_data and unreliable_data are now ready.
1458                                 Send them.
1459                         */
1460                         if(reliable_data.size() > 0)
1461                         {
1462                                 SharedBuffer<u8> reply(2 + reliable_data.size());
1463                                 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1464                                 memcpy((char*)&reply[2], reliable_data.c_str(),
1465                                                 reliable_data.size());
1466                                 // Send as reliable
1467                                 m_con.Send(client->peer_id, 0, reply, true);
1468                         }
1469                         if(unreliable_data.size() > 0)
1470                         {
1471                                 SharedBuffer<u8> reply(2 + unreliable_data.size());
1472                                 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1473                                 memcpy((char*)&reply[2], unreliable_data.c_str(),
1474                                                 unreliable_data.size());
1475                                 // Send as unreliable
1476                                 m_con.Send(client->peer_id, 0, reply, false);
1477                         }
1478
1479                         /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1480                         {
1481                                 dstream<<"INFO: Server: Size of object message data: "
1482                                                 <<"reliable: "<<reliable_data.size()
1483                                                 <<", unreliable: "<<unreliable_data.size()
1484                                                 <<std::endl;
1485                         }*/
1486                 }
1487
1488                 // Clear buffered_messages
1489                 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1490                                 i = buffered_messages.getIterator();
1491                                 i.atEnd()==false; i++)
1492                 {
1493                         delete i.getNode()->getValue();
1494                 }
1495         }
1496
1497         } // enable_experimental
1498
1499         /*
1500                 Send queued-for-sending map edit events.
1501         */
1502         {
1503                 while(m_unsent_map_edit_queue.size() != 0)
1504                 {
1505                         MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1506
1507                         if(event->type == MEET_ADDNODE)
1508                         {
1509                                 dstream<<"Server: MEET_ADDNODE"<<std::endl;
1510                                 sendAddNode(event->p, event->n, event->already_known_by_peer);
1511                         }
1512                         else if(event->type == MEET_REMOVENODE)
1513                         {
1514                                 dstream<<"Server: MEET_REMOVENODE"<<std::endl;
1515                                 sendRemoveNode(event->p, event->already_known_by_peer);
1516                         }
1517                         else if(event->type == MEET_OTHER)
1518                         {
1519                                 dstream<<"WARNING: Server: MEET_OTHER not implemented"
1520                                                 <<std::endl;
1521                         }
1522                         else
1523                         {
1524                                 dstream<<"WARNING: Server: Unknown MapEditEvent "
1525                                                 <<((u32)event->type)<<std::endl;
1526                         }
1527
1528                         delete event;
1529                 }
1530         }
1531
1532         /*
1533                 Send object positions
1534                 TODO: Get rid of MapBlockObjects
1535         */
1536         {
1537                 float &counter = m_objectdata_timer;
1538                 counter += dtime;
1539                 if(counter >= g_settings.getFloat("objectdata_interval"))
1540                 {
1541                         JMutexAutoLock lock1(m_env_mutex);
1542                         JMutexAutoLock lock2(m_con_mutex);
1543                         SendObjectData(counter);
1544
1545                         counter = 0.0;
1546                 }
1547         }
1548         
1549         /*
1550                 Step node metadata
1551         */
1552         {
1553                 JMutexAutoLock envlock(m_env_mutex);
1554                 JMutexAutoLock conlock(m_con_mutex);
1555                 
1556                 core::map<v3s16, MapBlock*> changed_blocks;
1557                 m_env.getMap().nodeMetadataStep(dtime, changed_blocks);
1558
1559                 for(core::map<v3s16, MapBlock*>::Iterator
1560                                 i = changed_blocks.getIterator();
1561                                 i.atEnd() == false; i++)
1562                 {
1563                         MapBlock *block = i.getNode()->getValue();
1564
1565                         for(core::map<u16, RemoteClient*>::Iterator
1566                                 i = m_clients.getIterator();
1567                                 i.atEnd()==false; i++)
1568                         {
1569                                 RemoteClient *client = i.getNode()->getValue();
1570                                 client->SetBlockNotSent(block->getPos());
1571                         }
1572                 }
1573         }
1574                 
1575         /*
1576                 Trigger emergethread (it somehow gets to a non-triggered but
1577                 bysy state sometimes)
1578         */
1579         {
1580                 float &counter = m_emergethread_trigger_timer;
1581                 counter += dtime;
1582                 if(counter >= 2.0)
1583                 {
1584                         counter = 0.0;
1585                         
1586                         m_emergethread.trigger();
1587                 }
1588         }
1589
1590         // Save map
1591         {
1592                 float &counter = m_savemap_timer;
1593                 counter += dtime;
1594                 if(counter >= g_settings.getFloat("server_map_save_interval"))
1595                 {
1596                         counter = 0.0;
1597
1598                         JMutexAutoLock lock(m_env_mutex);
1599
1600                         if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == true)
1601                         {
1602                                 // Save only changed parts
1603                                 m_env.getMap().save(true);
1604
1605                                 // Delete unused sectors
1606                                 u32 deleted_count = m_env.getMap().deleteUnusedSectors(
1607                                                 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1608                                 if(deleted_count > 0)
1609                                 {
1610                                         dout_server<<"Server: Unloaded "<<deleted_count
1611                                                         <<" sectors from memory"<<std::endl;
1612                                 }
1613
1614                                 // Save players
1615                                 m_env.serializePlayers(m_mapsavedir);
1616                         }
1617                 }
1618         }
1619 }
1620
1621 void Server::Receive()
1622 {
1623         DSTACK(__FUNCTION_NAME);
1624         u32 data_maxsize = 10000;
1625         Buffer<u8> data(data_maxsize);
1626         u16 peer_id;
1627         u32 datasize;
1628         try{
1629                 {
1630                         JMutexAutoLock conlock(m_con_mutex);
1631                         datasize = m_con.Receive(peer_id, *data, data_maxsize);
1632                 }
1633
1634                 // This has to be called so that the client list gets synced
1635                 // with the peer list of the connection
1636                 handlePeerChanges();
1637
1638                 ProcessData(*data, datasize, peer_id);
1639         }
1640         catch(con::InvalidIncomingDataException &e)
1641         {
1642                 derr_server<<"Server::Receive(): "
1643                                 "InvalidIncomingDataException: what()="
1644                                 <<e.what()<<std::endl;
1645         }
1646         catch(con::PeerNotFoundException &e)
1647         {
1648                 //NOTE: This is not needed anymore
1649                 
1650                 // The peer has been disconnected.
1651                 // Find the associated player and remove it.
1652
1653                 /*JMutexAutoLock envlock(m_env_mutex);
1654
1655                 dout_server<<"ServerThread: peer_id="<<peer_id
1656                                 <<" has apparently closed connection. "
1657                                 <<"Removing player."<<std::endl;
1658
1659                 m_env.removePlayer(peer_id);*/
1660         }
1661 }
1662
1663 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1664 {
1665         DSTACK(__FUNCTION_NAME);
1666         // Environment is locked first.
1667         JMutexAutoLock envlock(m_env_mutex);
1668         JMutexAutoLock conlock(m_con_mutex);
1669         
1670         con::Peer *peer;
1671         try{
1672                 peer = m_con.GetPeer(peer_id);
1673         }
1674         catch(con::PeerNotFoundException &e)
1675         {
1676                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1677                                 <<peer_id<<" not found"<<std::endl;
1678                 return;
1679         }
1680         
1681         u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1682
1683         try
1684         {
1685
1686         if(datasize < 2)
1687                 return;
1688
1689         ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1690         
1691         if(command == TOSERVER_INIT)
1692         {
1693                 // [0] u16 TOSERVER_INIT
1694                 // [2] u8 SER_FMT_VER_HIGHEST
1695                 // [3] u8[20] player_name
1696
1697                 if(datasize < 3)
1698                         return;
1699
1700                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1701                                 <<peer->id<<std::endl;
1702
1703                 // First byte after command is maximum supported
1704                 // serialization version
1705                 u8 client_max = data[2];
1706                 u8 our_max = SER_FMT_VER_HIGHEST;
1707                 // Use the highest version supported by both
1708                 u8 deployed = core::min_(client_max, our_max);
1709                 // If it's lower than the lowest supported, give up.
1710                 if(deployed < SER_FMT_VER_LOWEST)
1711                         deployed = SER_FMT_VER_INVALID;
1712
1713                 //peer->serialization_version = deployed;
1714                 getClient(peer->id)->pending_serialization_version = deployed;
1715
1716                 if(deployed == SER_FMT_VER_INVALID)
1717                 {
1718                         derr_server<<DTIME<<"Server: Cannot negotiate "
1719                                         "serialization version with peer "
1720                                         <<peer_id<<std::endl;
1721                         return;
1722                 }
1723
1724                 /*
1725                         Set up player
1726                 */
1727                 
1728                 // Get player name
1729                 const u32 playername_size = 20;
1730                 char playername[playername_size];
1731                 for(u32 i=0; i<playername_size-1; i++)
1732                 {
1733                         playername[i] = data[3+i];
1734                 }
1735                 playername[playername_size-1] = 0;
1736                 
1737                 // Get player
1738                 Player *player = emergePlayer(playername, "", peer_id);
1739                 //Player *player = m_env.getPlayer(peer_id);
1740
1741                 /*{
1742                         // DEBUG: Test serialization
1743                         std::ostringstream test_os;
1744                         player->serialize(test_os);
1745                         dstream<<"Player serialization test: \""<<test_os.str()
1746                                         <<"\""<<std::endl;
1747                         std::istringstream test_is(test_os.str());
1748                         player->deSerialize(test_is);
1749                 }*/
1750
1751                 // If failed, cancel
1752                 if(player == NULL)
1753                 {
1754                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
1755                                         <<": failed to emerge player"<<std::endl;
1756                         return;
1757                 }
1758
1759                 /*
1760                 // If a client is already connected to the player, cancel
1761                 if(player->peer_id != 0)
1762                 {
1763                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
1764                                         <<" tried to connect to "
1765                                         "an already connected player (peer_id="
1766                                         <<player->peer_id<<")"<<std::endl;
1767                         return;
1768                 }
1769                 // Set client of player
1770                 player->peer_id = peer_id;
1771                 */
1772
1773                 // Check if player doesn't exist
1774                 if(player == NULL)
1775                         throw con::InvalidIncomingDataException
1776                                 ("Server::ProcessData(): INIT: Player doesn't exist");
1777
1778                 /*// update name if it was supplied
1779                 if(datasize >= 20+3)
1780                 {
1781                         data[20+3-1] = 0;
1782                         player->updateName((const char*)&data[3]);
1783                 }*/
1784
1785                 // Now answer with a TOCLIENT_INIT
1786                 
1787                 SharedBuffer<u8> reply(2+1+6+8);
1788                 writeU16(&reply[0], TOCLIENT_INIT);
1789                 writeU8(&reply[2], deployed);
1790                 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
1791                 //writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
1792                 
1793                 // Send as reliable
1794                 m_con.Send(peer_id, 0, reply, true);
1795
1796                 return;
1797         }
1798         if(command == TOSERVER_INIT2)
1799         {
1800                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
1801                                 <<peer->id<<std::endl;
1802
1803
1804                 getClient(peer->id)->serialization_version
1805                                 = getClient(peer->id)->pending_serialization_version;
1806
1807                 /*
1808                         Send some initialization data
1809                 */
1810                 
1811                 // Send player info to all players
1812                 SendPlayerInfos();
1813
1814                 // Send inventory to player
1815                 SendInventory(peer->id);
1816                 
1817                 // Send time of day
1818                 {
1819                         SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1820                                         m_time_of_day.get());
1821                         m_con.Send(peer->id, 0, data, true);
1822                 }
1823                 
1824                 // Send information about server to player in chat
1825                 SendChatMessage(peer_id, getStatusString());
1826                 
1827                 // Send information about joining in chat
1828                 {
1829                         std::wstring name = L"unknown";
1830                         Player *player = m_env.getPlayer(peer_id);
1831                         if(player != NULL)
1832                                 name = narrow_to_wide(player->getName());
1833                         
1834                         std::wstring message;
1835                         message += L"*** ";
1836                         message += name;
1837                         message += L" joined game";
1838                         BroadcastChatMessage(message);
1839                 }
1840
1841                 return;
1842         }
1843
1844         if(peer_ser_ver == SER_FMT_VER_INVALID)
1845         {
1846                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
1847                                 " serialization format invalid or not initialized."
1848                                 " Skipping incoming command="<<command<<std::endl;
1849                 return;
1850         }
1851         
1852         Player *player = m_env.getPlayer(peer_id);
1853
1854         if(player == NULL){
1855                 derr_server<<"Server::ProcessData(): Cancelling: "
1856                                 "No player for peer_id="<<peer_id
1857                                 <<std::endl;
1858                 return;
1859         }
1860         if(command == TOSERVER_PLAYERPOS)
1861         {
1862                 if(datasize < 2+12+12+4+4)
1863                         return;
1864         
1865                 u32 start = 0;
1866                 v3s32 ps = readV3S32(&data[start+2]);
1867                 v3s32 ss = readV3S32(&data[start+2+12]);
1868                 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1869                 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1870                 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1871                 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1872                 pitch = wrapDegrees(pitch);
1873                 yaw = wrapDegrees(yaw);
1874                 player->setPosition(position);
1875                 player->setSpeed(speed);
1876                 player->setPitch(pitch);
1877                 player->setYaw(yaw);
1878                 
1879                 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1880                                 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1881                                 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1882         }
1883         else if(command == TOSERVER_GOTBLOCKS)
1884         {
1885                 if(datasize < 2+1)
1886                         return;
1887                 
1888                 /*
1889                         [0] u16 command
1890                         [2] u8 count
1891                         [3] v3s16 pos_0
1892                         [3+6] v3s16 pos_1
1893                         ...
1894                 */
1895
1896                 u16 count = data[2];
1897                 for(u16 i=0; i<count; i++)
1898                 {
1899                         if((s16)datasize < 2+1+(i+1)*6)
1900                                 throw con::InvalidIncomingDataException
1901                                         ("GOTBLOCKS length is too short");
1902                         v3s16 p = readV3S16(&data[2+1+i*6]);
1903                         /*dstream<<"Server: GOTBLOCKS ("
1904                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1905                         RemoteClient *client = getClient(peer_id);
1906                         client->GotBlock(p);
1907                 }
1908         }
1909         else if(command == TOSERVER_DELETEDBLOCKS)
1910         {
1911                 if(datasize < 2+1)
1912                         return;
1913                 
1914                 /*
1915                         [0] u16 command
1916                         [2] u8 count
1917                         [3] v3s16 pos_0
1918                         [3+6] v3s16 pos_1
1919                         ...
1920                 */
1921
1922                 u16 count = data[2];
1923                 for(u16 i=0; i<count; i++)
1924                 {
1925                         if((s16)datasize < 2+1+(i+1)*6)
1926                                 throw con::InvalidIncomingDataException
1927                                         ("DELETEDBLOCKS length is too short");
1928                         v3s16 p = readV3S16(&data[2+1+i*6]);
1929                         /*dstream<<"Server: DELETEDBLOCKS ("
1930                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1931                         RemoteClient *client = getClient(peer_id);
1932                         client->SetBlockNotSent(p);
1933                 }
1934         }
1935         else if(command == TOSERVER_CLICK_OBJECT)
1936         {
1937                 if(datasize < 13)
1938                         return;
1939
1940                 /*
1941                         [0] u16 command
1942                         [2] u8 button (0=left, 1=right)
1943                         [3] v3s16 block
1944                         [9] s16 id
1945                         [11] u16 item
1946                 */
1947                 u8 button = readU8(&data[2]);
1948                 v3s16 p;
1949                 p.X = readS16(&data[3]);
1950                 p.Y = readS16(&data[5]);
1951                 p.Z = readS16(&data[7]);
1952                 s16 id = readS16(&data[9]);
1953                 //u16 item_i = readU16(&data[11]);
1954
1955                 MapBlock *block = NULL;
1956                 try
1957                 {
1958                         block = m_env.getMap().getBlockNoCreate(p);
1959                 }
1960                 catch(InvalidPositionException &e)
1961                 {
1962                         derr_server<<"CLICK_OBJECT block not found"<<std::endl;
1963                         return;
1964                 }
1965
1966                 MapBlockObject *obj = block->getObject(id);
1967
1968                 if(obj == NULL)
1969                 {
1970                         derr_server<<"CLICK_OBJECT object not found"<<std::endl;
1971                         return;
1972                 }
1973
1974                 //TODO: Check that object is reasonably close
1975                 
1976                 // Left click
1977                 if(button == 0)
1978                 {
1979                         InventoryList *ilist = player->inventory.getList("main");
1980                         if(g_settings.getBool("creative_mode") == false && ilist != NULL)
1981                         {
1982                         
1983                                 // Skip if inventory has no free space
1984                                 if(ilist->getUsedSlots() == ilist->getSize())
1985                                 {
1986                                         dout_server<<"Player inventory has no free space"<<std::endl;
1987                                         return;
1988                                 }
1989                                 
1990                                 /*
1991                                         Create the inventory item
1992                                 */
1993                                 InventoryItem *item = NULL;
1994                                 // If it is an item-object, take the item from it
1995                                 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
1996                                 {
1997                                         item = ((ItemObject*)obj)->createInventoryItem();
1998                                 }
1999                                 // Else create an item of the object
2000                                 else
2001                                 {
2002                                         item = new MapBlockObjectItem
2003                                                         (obj->getInventoryString());
2004                                 }
2005                                 
2006                                 // Add to inventory and send inventory
2007                                 ilist->addItem(item);
2008                                 SendInventory(player->peer_id);
2009                         }
2010
2011                         // Remove from block
2012                         block->removeObject(id);
2013                 }
2014         }
2015         else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2016         {
2017                 if(datasize < 7)
2018                         return;
2019
2020                 /*
2021                         length: 7
2022                         [0] u16 command
2023                         [2] u8 button (0=left, 1=right)
2024                         [3] u16 id
2025                         [5] u16 item
2026                 */
2027                 u8 button = readU8(&data[2]);
2028                 u16 id = readS16(&data[3]);
2029                 //u16 item_i = readU16(&data[11]);
2030         
2031                 ServerActiveObject *obj = m_env.getActiveObject(id);
2032
2033                 if(obj == NULL)
2034                 {
2035                         derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2036                                         <<std::endl;
2037                         return;
2038                 }
2039
2040                 //TODO: Check that object is reasonably close
2041                 
2042                 // Left click, pick object up (usually)
2043                 if(button == 0)
2044                 {
2045                         InventoryList *ilist = player->inventory.getList("main");
2046                         if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2047                         {
2048                         
2049                                 // Skip if inventory has no free space
2050                                 if(ilist->getUsedSlots() == ilist->getSize())
2051                                 {
2052                                         dout_server<<"Player inventory has no free space"<<std::endl;
2053                                         return;
2054                                 }
2055
2056                                 // Skip if object has been removed
2057                                 if(obj->m_removed)
2058                                         return;
2059                                 
2060                                 /*
2061                                         Create the inventory item
2062                                 */
2063                                 InventoryItem *item = obj->createPickedUpItem();
2064                                 
2065                                 if(item)
2066                                 {
2067                                         // Add to inventory and send inventory
2068                                         ilist->addItem(item);
2069                                         SendInventory(player->peer_id);
2070
2071                                         // Remove object from environment
2072                                         obj->m_removed = true;
2073                                 }
2074                         }
2075                 }
2076         }
2077         else if(command == TOSERVER_GROUND_ACTION)
2078         {
2079                 if(datasize < 17)
2080                         return;
2081                 /*
2082                         length: 17
2083                         [0] u16 command
2084                         [2] u8 action
2085                         [3] v3s16 nodepos_undersurface
2086                         [9] v3s16 nodepos_abovesurface
2087                         [15] u16 item
2088                         actions:
2089                         0: start digging
2090                         1: place block
2091                         2: stop digging (all parameters ignored)
2092                         3: digging completed
2093                 */
2094                 u8 action = readU8(&data[2]);
2095                 v3s16 p_under;
2096                 p_under.X = readS16(&data[3]);
2097                 p_under.Y = readS16(&data[5]);
2098                 p_under.Z = readS16(&data[7]);
2099                 v3s16 p_over;
2100                 p_over.X = readS16(&data[9]);
2101                 p_over.Y = readS16(&data[11]);
2102                 p_over.Z = readS16(&data[13]);
2103                 u16 item_i = readU16(&data[15]);
2104
2105                 //TODO: Check that target is reasonably close
2106                 
2107                 /*
2108                         0: start digging
2109                 */
2110                 if(action == 0)
2111                 {
2112                         /*
2113                                 NOTE: This can be used in the future to check if
2114                                 somebody is cheating, by checking the timing.
2115                         */
2116                 } // action == 0
2117
2118                 /*
2119                         2: stop digging
2120                 */
2121                 else if(action == 2)
2122                 {
2123 #if 0
2124                         RemoteClient *client = getClient(peer->id);
2125                         JMutexAutoLock digmutex(client->m_dig_mutex);
2126                         client->m_dig_tool_item = -1;
2127 #endif
2128                 }
2129
2130                 /*
2131                         3: Digging completed
2132                 */
2133                 else if(action == 3)
2134                 {
2135                         // Mandatory parameter; actually used for nothing
2136                         core::map<v3s16, MapBlock*> modified_blocks;
2137
2138                         u8 material;
2139                         u8 mineral = MINERAL_NONE;
2140
2141                         bool cannot_remove_node = false;
2142
2143                         try
2144                         {
2145                                 MapNode n = m_env.getMap().getNode(p_under);
2146                                 // Get mineral
2147                                 mineral = n.getMineral();
2148                                 // Get material at position
2149                                 material = n.d;
2150                                 // If not yet cancelled
2151                                 if(cannot_remove_node == false)
2152                                 {
2153                                         // If it's not diggable, do nothing
2154                                         if(content_diggable(material) == false)
2155                                         {
2156                                                 derr_server<<"Server: Not finishing digging: "
2157                                                                 <<"Node not diggable"
2158                                                                 <<std::endl;
2159                                                 cannot_remove_node = true;
2160                                         }
2161                                 }
2162                                 // If not yet cancelled
2163                                 if(cannot_remove_node == false)
2164                                 {
2165                                         // Get node metadata
2166                                         NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2167                                         if(meta && meta->nodeRemovalDisabled() == true)
2168                                         {
2169                                                 derr_server<<"Server: Not finishing digging: "
2170                                                                 <<"Node metadata disables removal"
2171                                                                 <<std::endl;
2172                                                 cannot_remove_node = true;
2173                                         }
2174                                 }
2175                         }
2176                         catch(InvalidPositionException &e)
2177                         {
2178                                 derr_server<<"Server: Not finishing digging: Node not found."
2179                                                 <<" Adding block to emerge queue."
2180                                                 <<std::endl;
2181                                 m_emerge_queue.addBlock(peer_id,
2182                                                 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2183                                 cannot_remove_node = true;
2184                         }
2185
2186                         /*
2187                                 If node can't be removed, set block to be re-sent to
2188                                 client and quit.
2189                         */
2190                         if(cannot_remove_node)
2191                         {
2192                                 derr_server<<"Server: Not finishing digging."<<std::endl;
2193
2194                                 // Client probably has wrong data.
2195                                 // Set block not sent, so that client will get
2196                                 // a valid one.
2197                                 dstream<<"Client "<<peer_id<<" tried to dig "
2198                                                 <<"node; but node cannot be removed."
2199                                                 <<" setting MapBlock not sent."<<std::endl;
2200                                 RemoteClient *client = getClient(peer_id);
2201                                 v3s16 blockpos = getNodeBlockPos(p_under);
2202                                 client->SetBlockNotSent(blockpos);
2203                                         
2204                                 return;
2205                         }
2206                         
2207                         /*
2208                                 Send the removal to all other clients.
2209                                 - If other player is close, send REMOVENODE
2210                                 - Otherwise set blocks not sent
2211                         */
2212                         core::list<u16> far_players;
2213                         sendRemoveNode(p_under, peer_id, &far_players, 100);
2214                         
2215                         /*
2216                                 Update and send inventory
2217                         */
2218
2219                         if(g_settings.getBool("creative_mode") == false)
2220                         {
2221                                 /*
2222                                         Wear out tool
2223                                 */
2224                                 InventoryList *mlist = player->inventory.getList("main");
2225                                 if(mlist != NULL)
2226                                 {
2227                                         InventoryItem *item = mlist->getItem(item_i);
2228                                         if(item && (std::string)item->getName() == "ToolItem")
2229                                         {
2230                                                 ToolItem *titem = (ToolItem*)item;
2231                                                 std::string toolname = titem->getToolName();
2232
2233                                                 // Get digging properties for material and tool
2234                                                 DiggingProperties prop =
2235                                                                 getDiggingProperties(material, toolname);
2236
2237                                                 if(prop.diggable == false)
2238                                                 {
2239                                                         derr_server<<"Server: WARNING: Player digged"
2240                                                                         <<" with impossible material + tool"
2241                                                                         <<" combination"<<std::endl;
2242                                                 }
2243                                                 
2244                                                 bool weared_out = titem->addWear(prop.wear);
2245
2246                                                 if(weared_out)
2247                                                 {
2248                                                         mlist->deleteItem(item_i);
2249                                                 }
2250                                         }
2251                                 }
2252
2253                                 /*
2254                                         Add dug item to inventory
2255                                 */
2256
2257                                 InventoryItem *item = NULL;
2258
2259                                 if(mineral != MINERAL_NONE)
2260                                         item = getDiggedMineralItem(mineral);
2261                                 
2262                                 // If not mineral
2263                                 if(item == NULL)
2264                                 {
2265                                         std::string &dug_s = content_features(material).dug_item;
2266                                         if(dug_s != "")
2267                                         {
2268                                                 std::istringstream is(dug_s, std::ios::binary);
2269                                                 item = InventoryItem::deSerialize(is);
2270                                         }
2271                                 }
2272                                 
2273                                 if(item != NULL)
2274                                 {
2275                                         // Add a item to inventory
2276                                         player->inventory.addItem("main", item);
2277
2278                                         // Send inventory
2279                                         SendInventory(player->peer_id);
2280                                 }
2281                         }
2282
2283                         /*
2284                                 Remove the node
2285                                 (this takes some time so it is done after the quick stuff)
2286                         */
2287                         m_ignore_map_edit_events = true;
2288                         m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2289                         m_ignore_map_edit_events = false;
2290                         
2291                         /*
2292                                 Set blocks not sent to far players
2293                         */
2294                         for(core::list<u16>::Iterator
2295                                         i = far_players.begin();
2296                                         i != far_players.end(); i++)
2297                         {
2298                                 u16 peer_id = *i;
2299                                 RemoteClient *client = getClient(peer_id);
2300                                 if(client==NULL)
2301                                         continue;
2302                                 client->SetBlocksNotSent(modified_blocks);
2303                         }
2304                 }
2305                 
2306                 /*
2307                         1: place block
2308                 */
2309                 else if(action == 1)
2310                 {
2311
2312                         InventoryList *ilist = player->inventory.getList("main");
2313                         if(ilist == NULL)
2314                                 return;
2315
2316                         // Get item
2317                         InventoryItem *item = ilist->getItem(item_i);
2318                         
2319                         // If there is no item, it is not possible to add it anywhere
2320                         if(item == NULL)
2321                                 return;
2322                         
2323                         /*
2324                                 Handle material items
2325                         */
2326                         if(std::string("MaterialItem") == item->getName())
2327                         {
2328                                 try{
2329                                         // Don't add a node if this is not a free space
2330                                         MapNode n2 = m_env.getMap().getNode(p_over);
2331                                         if(content_buildable_to(n2.d) == false)
2332                                         {
2333                                                 // Client probably has wrong data.
2334                                                 // Set block not sent, so that client will get
2335                                                 // a valid one.
2336                                                 dstream<<"Client "<<peer_id<<" tried to place"
2337                                                                 <<" node in invalid position; setting"
2338                                                                 <<" MapBlock not sent."<<std::endl;
2339                                                 RemoteClient *client = getClient(peer_id);
2340                                                 v3s16 blockpos = getNodeBlockPos(p_over);
2341                                                 client->SetBlockNotSent(blockpos);
2342                                                 return;
2343                                         }
2344                                 }
2345                                 catch(InvalidPositionException &e)
2346                                 {
2347                                         derr_server<<"Server: Ignoring ADDNODE: Node not found"
2348                                                         <<" Adding block to emerge queue."
2349                                                         <<std::endl;
2350                                         m_emerge_queue.addBlock(peer_id,
2351                                                         getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2352                                         return;
2353                                 }
2354
2355                                 // Reset build time counter
2356                                 getClient(peer->id)->m_time_from_building = 0.0;
2357                                 
2358                                 // Create node data
2359                                 MaterialItem *mitem = (MaterialItem*)item;
2360                                 MapNode n;
2361                                 n.d = mitem->getMaterial();
2362                                 if(content_features(n.d).wall_mounted)
2363                                         n.dir = packDir(p_under - p_over);
2364                                 
2365                                 /*
2366                                         Send to all players
2367                                 */
2368                                 core::list<u16> far_players;
2369                                 sendAddNode(p_over, n, 0, &far_players, 100);
2370                                 
2371                                 /*
2372                                         Handle inventory
2373                                 */
2374                                 InventoryList *ilist = player->inventory.getList("main");
2375                                 if(g_settings.getBool("creative_mode") == false && ilist)
2376                                 {
2377                                         // Remove from inventory and send inventory
2378                                         if(mitem->getCount() == 1)
2379                                                 ilist->deleteItem(item_i);
2380                                         else
2381                                                 mitem->remove(1);
2382                                         // Send inventory
2383                                         SendInventory(peer_id);
2384                                 }
2385                                 
2386                                 /*
2387                                         Add node.
2388
2389                                         This takes some time so it is done after the quick stuff
2390                                 */
2391                                 core::map<v3s16, MapBlock*> modified_blocks;
2392                                 m_ignore_map_edit_events = true;
2393                                 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2394                                 m_ignore_map_edit_events = false;
2395                                 
2396                                 /*
2397                                         Set blocks not sent to far players
2398                                 */
2399                                 for(core::list<u16>::Iterator
2400                                                 i = far_players.begin();
2401                                                 i != far_players.end(); i++)
2402                                 {
2403                                         u16 peer_id = *i;
2404                                         RemoteClient *client = getClient(peer_id);
2405                                         if(client==NULL)
2406                                                 continue;
2407                                         client->SetBlocksNotSent(modified_blocks);
2408                                 }
2409
2410                                 /*
2411                                         Calculate special events
2412                                 */
2413                                 
2414                                 /*if(n.d == CONTENT_MESE)
2415                                 {
2416                                         u32 count = 0;
2417                                         for(s16 z=-1; z<=1; z++)
2418                                         for(s16 y=-1; y<=1; y++)
2419                                         for(s16 x=-1; x<=1; x++)
2420                                         {
2421                                                 
2422                                         }
2423                                 }*/
2424                         }
2425                         /*
2426                                 Place other item (not a block)
2427                         */
2428                         else
2429                         {
2430                                 v3s16 blockpos = getNodeBlockPos(p_over);
2431                                 
2432                                 /*
2433                                         Check that the block is loaded so that the item
2434                                         can properly be added to the static list too
2435                                 */
2436                                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2437                                 if(block==NULL)
2438                                 {
2439                                         derr_server<<"Error while placing object: "
2440                                                         "block not found"<<std::endl;
2441                                         return;
2442                                 }
2443
2444                                 dout_server<<"Placing a miscellaneous item on map"
2445                                                 <<std::endl;
2446                                 
2447                                 // Calculate a position for it
2448                                 v3f pos = intToFloat(p_over, BS);
2449                                 //pos.Y -= BS*0.45;
2450                                 pos.Y -= BS*0.25; // let it drop a bit
2451                                 // Randomize a bit
2452                                 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2453                                 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2454
2455                                 /*
2456                                         Create the object
2457                                 */
2458                                 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2459
2460                                 if(obj == NULL)
2461                                 {
2462                                         derr_server<<"WARNING: item resulted in NULL object, "
2463                                                         <<"not placing onto map"
2464                                                         <<std::endl;
2465                                 }
2466                                 else
2467                                 {
2468                                         // Add the object to the environment
2469                                         m_env.addActiveObject(obj);
2470                                         
2471                                         dout_server<<"Placed object"<<std::endl;
2472
2473                                         // If item has count<=1, delete it
2474                                         if(item->getCount() <= 1)
2475                                         {
2476                                                 InventoryList *ilist = player->inventory.getList("main");
2477                                                 if(g_settings.getBool("creative_mode") == false && ilist)
2478                                                 {
2479                                                         // Remove from inventory and send inventory
2480                                                         ilist->deleteItem(item_i);
2481                                                         // Send inventory
2482                                                         SendInventory(peer_id);
2483                                                 }
2484                                         }
2485                                         // Else decrement it
2486                                         else
2487                                         {
2488                                                 item->remove(1);
2489                                                 // Send inventory
2490                                                 SendInventory(peer_id);
2491                                         }
2492                                 }
2493                         }
2494
2495                 } // action == 1
2496
2497                 /*
2498                         Catch invalid actions
2499                 */
2500                 else
2501                 {
2502                         derr_server<<"WARNING: Server: Invalid action "
2503                                         <<action<<std::endl;
2504                 }
2505         }
2506 #if 0
2507         else if(command == TOSERVER_RELEASE)
2508         {
2509                 if(datasize < 3)
2510                         return;
2511                 /*
2512                         length: 3
2513                         [0] u16 command
2514                         [2] u8 button
2515                 */
2516                 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
2517         }
2518 #endif
2519         else if(command == TOSERVER_SIGNTEXT)
2520         {
2521                 /*
2522                         u16 command
2523                         v3s16 blockpos
2524                         s16 id
2525                         u16 textlen
2526                         textdata
2527                 */
2528                 std::string datastring((char*)&data[2], datasize-2);
2529                 std::istringstream is(datastring, std::ios_base::binary);
2530                 u8 buf[6];
2531                 // Read stuff
2532                 is.read((char*)buf, 6);
2533                 v3s16 blockpos = readV3S16(buf);
2534                 is.read((char*)buf, 2);
2535                 s16 id = readS16(buf);
2536                 is.read((char*)buf, 2);
2537                 u16 textlen = readU16(buf);
2538                 std::string text;
2539                 for(u16 i=0; i<textlen; i++)
2540                 {
2541                         is.read((char*)buf, 1);
2542                         text += (char)buf[0];
2543                 }
2544
2545                 MapBlock *block = NULL;
2546                 try
2547                 {
2548                         block = m_env.getMap().getBlockNoCreate(blockpos);
2549                 }
2550                 catch(InvalidPositionException &e)
2551                 {
2552                         derr_server<<"Error while setting sign text: "
2553                                         "block not found"<<std::endl;
2554                         return;
2555                 }
2556
2557                 MapBlockObject *obj = block->getObject(id);
2558                 if(obj == NULL)
2559                 {
2560                         derr_server<<"Error while setting sign text: "
2561                                         "object not found"<<std::endl;
2562                         return;
2563                 }
2564                 
2565                 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
2566                 {
2567                         derr_server<<"Error while setting sign text: "
2568                                         "object is not a sign"<<std::endl;
2569                         return;
2570                 }
2571
2572                 ((SignObject*)obj)->setText(text);
2573
2574                 obj->getBlock()->setChangedFlag();
2575         }
2576         else if(command == TOSERVER_SIGNNODETEXT)
2577         {
2578                 /*
2579                         u16 command
2580                         v3s16 p
2581                         u16 textlen
2582                         textdata
2583                 */
2584                 std::string datastring((char*)&data[2], datasize-2);
2585                 std::istringstream is(datastring, std::ios_base::binary);
2586                 u8 buf[6];
2587                 // Read stuff
2588                 is.read((char*)buf, 6);
2589                 v3s16 p = readV3S16(buf);
2590                 is.read((char*)buf, 2);
2591                 u16 textlen = readU16(buf);
2592                 std::string text;
2593                 for(u16 i=0; i<textlen; i++)
2594                 {
2595                         is.read((char*)buf, 1);
2596                         text += (char)buf[0];
2597                 }
2598
2599                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
2600                 if(!meta)
2601                         return;
2602                 if(meta->typeId() != CONTENT_SIGN_WALL)
2603                         return;
2604                 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
2605                 signmeta->setText(text);
2606                 
2607                 v3s16 blockpos = getNodeBlockPos(p);
2608                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2609                 if(block)
2610                 {
2611                         block->setChangedFlag();
2612                 }
2613
2614                 for(core::map<u16, RemoteClient*>::Iterator
2615                         i = m_clients.getIterator();
2616                         i.atEnd()==false; i++)
2617                 {
2618                         RemoteClient *client = i.getNode()->getValue();
2619                         client->SetBlockNotSent(blockpos);
2620                 }
2621         }
2622         else if(command == TOSERVER_INVENTORY_ACTION)
2623         {
2624                 /*// Ignore inventory changes if in creative mode
2625                 if(g_settings.getBool("creative_mode") == true)
2626                 {
2627                         dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
2628                                         <<std::endl;
2629                         return;
2630                 }*/
2631                 // Strip command and create a stream
2632                 std::string datastring((char*)&data[2], datasize-2);
2633                 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2634                 std::istringstream is(datastring, std::ios_base::binary);
2635                 // Create an action
2636                 InventoryAction *a = InventoryAction::deSerialize(is);
2637                 if(a != NULL)
2638                 {
2639                         // Create context
2640                         InventoryContext c;
2641                         c.current_player = player;
2642
2643                         /*
2644                                 Handle craftresult specially if not in creative mode
2645                         */
2646                         bool disable_action = false;
2647                         if(a->getType() == IACTION_MOVE
2648                                         && g_settings.getBool("creative_mode") == false)
2649                         {
2650                                 IMoveAction *ma = (IMoveAction*)a;
2651                                 if(ma->to_inv == "current_player" &&
2652                                                 ma->from_inv == "current_player")
2653                                 {
2654                                         InventoryList *rlist = player->inventory.getList("craftresult");
2655                                         assert(rlist);
2656                                         InventoryList *clist = player->inventory.getList("craft");
2657                                         assert(clist);
2658                                         InventoryList *mlist = player->inventory.getList("main");
2659                                         assert(mlist);
2660                                         /*
2661                                                 Craftresult is no longer preview if something
2662                                                 is moved into it
2663                                         */
2664                                         if(ma->to_list == "craftresult"
2665                                                         && ma->from_list != "craftresult")
2666                                         {
2667                                                 // If it currently is a preview, remove
2668                                                 // its contents
2669                                                 if(player->craftresult_is_preview)
2670                                                 {
2671                                                         rlist->deleteItem(0);
2672                                                 }
2673                                                 player->craftresult_is_preview = false;
2674                                         }
2675                                         /*
2676                                                 Crafting takes place if this condition is true.
2677                                         */
2678                                         if(player->craftresult_is_preview &&
2679                                                         ma->from_list == "craftresult")
2680                                         {
2681                                                 player->craftresult_is_preview = false;
2682                                                 clist->decrementMaterials(1);
2683                                         }
2684                                         /*
2685                                                 If the craftresult is placed on itself, move it to
2686                                                 main inventory instead of doing the action
2687                                         */
2688                                         if(ma->to_list == "craftresult"
2689                                                         && ma->from_list == "craftresult")
2690                                         {
2691                                                 disable_action = true;
2692                                                 
2693                                                 InventoryItem *item1 = rlist->changeItem(0, NULL);
2694                                                 mlist->addItem(item1);
2695                                         }
2696                                 }
2697                         }
2698                         
2699                         if(disable_action == false)
2700                         {
2701                                 // Feed action to player inventory
2702                                 a->apply(&c, this);
2703                                 // Eat the action
2704                                 delete a;
2705                         }
2706                         else
2707                         {
2708                                 // Send inventory
2709                                 SendInventory(player->peer_id);
2710                         }
2711                 }
2712                 else
2713                 {
2714                         dstream<<"TOSERVER_INVENTORY_ACTION: "
2715                                         <<"InventoryAction::deSerialize() returned NULL"
2716                                         <<std::endl;
2717                 }
2718         }
2719         else if(command == TOSERVER_CHAT_MESSAGE)
2720         {
2721                 /*
2722                         u16 command
2723                         u16 length
2724                         wstring message
2725                 */
2726                 u8 buf[6];
2727                 std::string datastring((char*)&data[2], datasize-2);
2728                 std::istringstream is(datastring, std::ios_base::binary);
2729                 
2730                 // Read stuff
2731                 is.read((char*)buf, 2);
2732                 u16 len = readU16(buf);
2733                 
2734                 std::wstring message;
2735                 for(u16 i=0; i<len; i++)
2736                 {
2737                         is.read((char*)buf, 2);
2738                         message += (wchar_t)readU16(buf);
2739                 }
2740
2741                 // Get player name of this client
2742                 std::wstring name = narrow_to_wide(player->getName());
2743                 
2744                 // Line to send to players
2745                 std::wstring line;
2746                 // Whether to send to the player that sent the line
2747                 bool send_to_sender = false;
2748                 // Whether to send to other players
2749                 bool send_to_others = false;
2750                 
2751                 // Parse commands
2752                 std::wstring commandprefix = L"/#";
2753                 if(message.substr(0, commandprefix.size()) == commandprefix)
2754                 {
2755                         line += L"Server: ";
2756
2757                         message = message.substr(commandprefix.size());
2758                         // Get player name as narrow string
2759                         std::string name_s = player->getName();
2760                         // Convert message to narrow string
2761                         std::string message_s = wide_to_narrow(message);
2762                         // Operator is the single name defined in config.
2763                         std::string operator_name = g_settings.get("name");
2764                         bool is_operator = (operator_name != "" &&
2765                                         wide_to_narrow(name) == operator_name);
2766                         bool valid_command = false;
2767                         if(message_s == "help")
2768                         {
2769                                 line += L"-!- Available commands: ";
2770                                 line += L"status ";
2771                                 if(is_operator)
2772                                 {
2773                                         line += L"shutdown setting ";
2774                                 }
2775                                 else
2776                                 {
2777                                 }
2778                                 send_to_sender = true;
2779                                 valid_command = true;
2780                         }
2781                         else if(message_s == "status")
2782                         {
2783                                 line = getStatusString();
2784                                 send_to_sender = true;
2785                                 valid_command = true;
2786                         }
2787                         else if(is_operator)
2788                         {
2789                                 if(message_s == "shutdown")
2790                                 {
2791                                         dstream<<DTIME<<" Server: Operator requested shutdown."
2792                                                         <<std::endl;
2793                                         m_shutdown_requested.set(true);
2794                                         
2795                                         line += L"*** Server shutting down (operator request)";
2796                                         send_to_sender = true;
2797                                         valid_command = true;
2798                                 }
2799                                 else if(message_s.substr(0,8) == "setting ")
2800                                 {
2801                                         std::string confline = message_s.substr(8);
2802                                         g_settings.parseConfigLine(confline);
2803                                         line += L"-!- Setting changed.";
2804                                         send_to_sender = true;
2805                                         valid_command = true;
2806                                 }
2807                         }
2808                         
2809                         if(valid_command == false)
2810                         {
2811                                 line += L"-!- Invalid command: " + message;
2812                                 send_to_sender = true;
2813                         }
2814                 }
2815                 else
2816                 {
2817                         line += L"<";
2818                         /*if(is_operator)
2819                                 line += L"@";*/
2820                         line += name;
2821                         line += L"> ";
2822                         line += message;
2823                         send_to_others = true;
2824                 }
2825                 
2826                 if(line != L"")
2827                 {
2828                         dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2829
2830                         /*
2831                                 Send the message to clients
2832                         */
2833                         for(core::map<u16, RemoteClient*>::Iterator
2834                                 i = m_clients.getIterator();
2835                                 i.atEnd() == false; i++)
2836                         {
2837                                 // Get client and check that it is valid
2838                                 RemoteClient *client = i.getNode()->getValue();
2839                                 assert(client->peer_id == i.getNode()->getKey());
2840                                 if(client->serialization_version == SER_FMT_VER_INVALID)
2841                                         continue;
2842
2843                                 // Filter recipient
2844                                 bool sender_selected = (peer_id == client->peer_id);
2845                                 if(sender_selected == true && send_to_sender == false)
2846                                         continue;
2847                                 if(sender_selected == false && send_to_others == false)
2848                                         continue;
2849
2850                                 SendChatMessage(client->peer_id, line);
2851                         }
2852                 }
2853         }
2854         else
2855         {
2856                 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
2857                                 "unknown command "<<command<<std::endl;
2858         }
2859         
2860         } //try
2861         catch(SendFailedException &e)
2862         {
2863                 derr_server<<"Server::ProcessData(): SendFailedException: "
2864                                 <<"what="<<e.what()
2865                                 <<std::endl;
2866         }
2867 }
2868
2869 void Server::onMapEditEvent(MapEditEvent *event)
2870 {
2871         dstream<<"Server::onMapEditEvent()"<<std::endl;
2872         if(m_ignore_map_edit_events)
2873                 return;
2874         MapEditEvent *e = event->clone();
2875         m_unsent_map_edit_queue.push_back(e);
2876 }
2877
2878 Inventory* Server::getInventory(InventoryContext *c, std::string id)
2879 {
2880         if(id == "current_player")
2881         {
2882                 assert(c->current_player);
2883                 return &(c->current_player->inventory);
2884         }
2885         
2886         Strfnd fn(id);
2887         std::string id0 = fn.next(":");
2888
2889         if(id0 == "nodemeta")
2890         {
2891                 v3s16 p;
2892                 p.X = stoi(fn.next(","));
2893                 p.Y = stoi(fn.next(","));
2894                 p.Z = stoi(fn.next(","));
2895                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
2896                 if(meta)
2897                         return meta->getInventory();
2898                 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
2899                                 <<"no metadata found"<<std::endl;
2900                 return NULL;
2901         }
2902
2903         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
2904         return NULL;
2905 }
2906 void Server::inventoryModified(InventoryContext *c, std::string id)
2907 {
2908         if(id == "current_player")
2909         {
2910                 assert(c->current_player);
2911                 // Send inventory
2912                 SendInventory(c->current_player->peer_id);
2913                 return;
2914         }
2915         
2916         Strfnd fn(id);
2917         std::string id0 = fn.next(":");
2918
2919         if(id0 == "nodemeta")
2920         {
2921                 v3s16 p;
2922                 p.X = stoi(fn.next(","));
2923                 p.Y = stoi(fn.next(","));
2924                 p.Z = stoi(fn.next(","));
2925                 v3s16 blockpos = getNodeBlockPos(p);
2926
2927                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
2928                 if(meta)
2929                         meta->inventoryModified();
2930
2931                 for(core::map<u16, RemoteClient*>::Iterator
2932                         i = m_clients.getIterator();
2933                         i.atEnd()==false; i++)
2934                 {
2935                         RemoteClient *client = i.getNode()->getValue();
2936                         client->SetBlockNotSent(blockpos);
2937                 }
2938
2939                 return;
2940         }
2941
2942         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
2943 }
2944
2945 core::list<PlayerInfo> Server::getPlayerInfo()
2946 {
2947         DSTACK(__FUNCTION_NAME);
2948         JMutexAutoLock envlock(m_env_mutex);
2949         JMutexAutoLock conlock(m_con_mutex);
2950         
2951         core::list<PlayerInfo> list;
2952
2953         core::list<Player*> players = m_env.getPlayers();
2954         
2955         core::list<Player*>::Iterator i;
2956         for(i = players.begin();
2957                         i != players.end(); i++)
2958         {
2959                 PlayerInfo info;
2960
2961                 Player *player = *i;
2962
2963                 try{
2964                         con::Peer *peer = m_con.GetPeer(player->peer_id);
2965                         // Copy info from peer to info struct
2966                         info.id = peer->id;
2967                         info.address = peer->address;
2968                         info.avg_rtt = peer->avg_rtt;
2969                 }
2970                 catch(con::PeerNotFoundException &e)
2971                 {
2972                         // Set dummy peer info
2973                         info.id = 0;
2974                         info.address = Address(0,0,0,0,0);
2975                         info.avg_rtt = 0.0;
2976                 }
2977
2978                 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
2979                 info.position = player->getPosition();
2980
2981                 list.push_back(info);
2982         }
2983
2984         return list;
2985 }
2986
2987
2988 void Server::peerAdded(con::Peer *peer)
2989 {
2990         DSTACK(__FUNCTION_NAME);
2991         dout_server<<"Server::peerAdded(): peer->id="
2992                         <<peer->id<<std::endl;
2993         
2994         PeerChange c;
2995         c.type = PEER_ADDED;
2996         c.peer_id = peer->id;
2997         c.timeout = false;
2998         m_peer_change_queue.push_back(c);
2999 }
3000
3001 void Server::deletingPeer(con::Peer *peer, bool timeout)
3002 {
3003         DSTACK(__FUNCTION_NAME);
3004         dout_server<<"Server::deletingPeer(): peer->id="
3005                         <<peer->id<<", timeout="<<timeout<<std::endl;
3006         
3007         PeerChange c;
3008         c.type = PEER_REMOVED;
3009         c.peer_id = peer->id;
3010         c.timeout = timeout;
3011         m_peer_change_queue.push_back(c);
3012 }
3013
3014 void Server::SendObjectData(float dtime)
3015 {
3016         DSTACK(__FUNCTION_NAME);
3017
3018         core::map<v3s16, bool> stepped_blocks;
3019         
3020         for(core::map<u16, RemoteClient*>::Iterator
3021                 i = m_clients.getIterator();
3022                 i.atEnd() == false; i++)
3023         {
3024                 u16 peer_id = i.getNode()->getKey();
3025                 RemoteClient *client = i.getNode()->getValue();
3026                 assert(client->peer_id == peer_id);
3027                 
3028                 if(client->serialization_version == SER_FMT_VER_INVALID)
3029                         continue;
3030                 
3031                 client->SendObjectData(this, dtime, stepped_blocks);
3032         }
3033 }
3034
3035 void Server::SendPlayerInfos()
3036 {
3037         DSTACK(__FUNCTION_NAME);
3038
3039         //JMutexAutoLock envlock(m_env_mutex);
3040         
3041         // Get connected players
3042         core::list<Player*> players = m_env.getPlayers(true);
3043         
3044         u32 player_count = players.getSize();
3045         u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3046
3047         SharedBuffer<u8> data(datasize);
3048         writeU16(&data[0], TOCLIENT_PLAYERINFO);
3049         
3050         u32 start = 2;
3051         core::list<Player*>::Iterator i;
3052         for(i = players.begin();
3053                         i != players.end(); i++)
3054         {
3055                 Player *player = *i;
3056
3057                 /*dstream<<"Server sending player info for player with "
3058                                 "peer_id="<<player->peer_id<<std::endl;*/
3059                 
3060                 writeU16(&data[start], player->peer_id);
3061                 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3062                 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3063                 start += 2+PLAYERNAME_SIZE;
3064         }
3065
3066         //JMutexAutoLock conlock(m_con_mutex);
3067
3068         // Send as reliable
3069         m_con.SendToAll(0, data, true);
3070 }
3071
3072 void Server::SendInventory(u16 peer_id)
3073 {
3074         DSTACK(__FUNCTION_NAME);
3075         
3076         Player* player = m_env.getPlayer(peer_id);
3077         assert(player);
3078
3079         /*
3080                 Calculate crafting stuff
3081         */
3082         if(g_settings.getBool("creative_mode") == false)
3083         {
3084                 InventoryList *clist = player->inventory.getList("craft");
3085                 InventoryList *rlist = player->inventory.getList("craftresult");
3086
3087                 if(rlist->getUsedSlots() == 0)
3088                         player->craftresult_is_preview = true;
3089
3090                 if(rlist && player->craftresult_is_preview)
3091                 {
3092                         rlist->clearItems();
3093                 }
3094                 if(clist && rlist && player->craftresult_is_preview)
3095                 {
3096                         InventoryItem *items[9];
3097                         for(u16 i=0; i<9; i++)
3098                         {
3099                                 items[i] = clist->getItem(i);
3100                         }
3101                         
3102                         bool found = false;
3103
3104                         // Wood
3105                         if(!found)
3106                         {
3107                                 ItemSpec specs[9];
3108                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_TREE);
3109                                 if(checkItemCombination(items, specs))
3110                                 {
3111                                         rlist->addItem(new MaterialItem(CONTENT_WOOD, 4));
3112                                         found = true;
3113                                 }
3114                         }
3115
3116                         // Stick
3117                         if(!found)
3118                         {
3119                                 ItemSpec specs[9];
3120                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3121                                 if(checkItemCombination(items, specs))
3122                                 {
3123                                         rlist->addItem(new CraftItem("Stick", 4));
3124                                         found = true;
3125                                 }
3126                         }
3127
3128                         // Sign
3129                         if(!found)
3130                         {
3131                                 ItemSpec specs[9];
3132                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3133                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3134                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3135                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3136                                 specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3137                                 specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3138                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3139                                 if(checkItemCombination(items, specs))
3140                                 {
3141                                         //rlist->addItem(new MapBlockObjectItem("Sign"));
3142                                         rlist->addItem(new MaterialItem(CONTENT_SIGN_WALL, 1));
3143                                         found = true;
3144                                 }
3145                         }
3146
3147                         // Torch
3148                         if(!found)
3149                         {
3150                                 ItemSpec specs[9];
3151                                 specs[0] = ItemSpec(ITEM_CRAFT, "lump_of_coal");
3152                                 specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
3153                                 if(checkItemCombination(items, specs))
3154                                 {
3155                                         rlist->addItem(new MaterialItem(CONTENT_TORCH, 4));
3156                                         found = true;
3157                                 }
3158                         }
3159
3160                         // Wooden pick
3161                         if(!found)
3162                         {
3163                                 ItemSpec specs[9];
3164                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3165                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3166                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3167                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3168                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3169                                 if(checkItemCombination(items, specs))
3170                                 {
3171                                         rlist->addItem(new ToolItem("WPick", 0));
3172                                         found = true;
3173                                 }
3174                         }
3175
3176                         // Stone pick
3177                         if(!found)
3178                         {
3179                                 ItemSpec specs[9];
3180                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3181                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3182                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3183                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3184                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3185                                 if(checkItemCombination(items, specs))
3186                                 {
3187                                         rlist->addItem(new ToolItem("STPick", 0));
3188                                         found = true;
3189                                 }
3190                         }
3191
3192                         // Steel pick
3193                         if(!found)
3194                         {
3195                                 ItemSpec specs[9];
3196                                 specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3197                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3198                                 specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3199                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3200                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3201                                 if(checkItemCombination(items, specs))
3202                                 {
3203                                         rlist->addItem(new ToolItem("SteelPick", 0));
3204                                         found = true;
3205                                 }
3206                         }
3207
3208                         // Mese pick
3209                         if(!found)
3210                         {
3211                                 ItemSpec specs[9];
3212                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
3213                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
3214                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
3215                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3216                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3217                                 if(checkItemCombination(items, specs))
3218                                 {
3219                                         rlist->addItem(new ToolItem("MesePick", 0));
3220                                         found = true;
3221                                 }
3222                         }
3223
3224                         // Wooden showel
3225                         if(!found)
3226                         {
3227                                 ItemSpec specs[9];
3228                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3229                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3230                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3231                                 if(checkItemCombination(items, specs))
3232                                 {
3233                                         rlist->addItem(new ToolItem("WShovel", 0));
3234                                         found = true;
3235                                 }
3236                         }
3237
3238                         // Stone showel
3239                         if(!found)
3240                         {
3241                                 ItemSpec specs[9];
3242                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3243                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3244                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3245                                 if(checkItemCombination(items, specs))
3246                                 {
3247                                         rlist->addItem(new ToolItem("STShovel", 0));
3248                                         found = true;
3249                                 }
3250                         }
3251
3252                         // Steel showel
3253                         if(!found)
3254                         {
3255                                 ItemSpec specs[9];
3256                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3257                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3258                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3259                                 if(checkItemCombination(items, specs))
3260                                 {
3261                                         rlist->addItem(new ToolItem("SteelShovel", 0));
3262                                         found = true;
3263                                 }
3264                         }
3265
3266                         // Wooden axe
3267                         if(!found)
3268                         {
3269                                 ItemSpec specs[9];
3270                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3271                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3272                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3273                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3274                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3275                                 if(checkItemCombination(items, specs))
3276                                 {
3277                                         rlist->addItem(new ToolItem("WAxe", 0));
3278                                         found = true;
3279                                 }
3280                         }
3281
3282                         // Stone axe
3283                         if(!found)
3284                         {
3285                                 ItemSpec specs[9];
3286                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3287                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3288                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3289                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3290                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3291                                 if(checkItemCombination(items, specs))
3292                                 {
3293                                         rlist->addItem(new ToolItem("STAxe", 0));
3294                                         found = true;
3295                                 }
3296                         }
3297
3298                         // Steel axe
3299                         if(!found)
3300                         {
3301                                 ItemSpec specs[9];
3302                                 specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3303                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3304                                 specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3305                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3306                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3307                                 if(checkItemCombination(items, specs))
3308                                 {
3309                                         rlist->addItem(new ToolItem("SteelAxe", 0));
3310                                         found = true;
3311                                 }
3312                         }
3313
3314                         // Chest
3315                         if(!found)
3316                         {
3317                                 ItemSpec specs[9];
3318                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3319                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3320                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3321                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3322                                 specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3323                                 specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3324                                 specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3325                                 specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3326                                 if(checkItemCombination(items, specs))
3327                                 {
3328                                         rlist->addItem(new MaterialItem(CONTENT_CHEST, 1));
3329                                         found = true;
3330                                 }
3331                         }
3332
3333                         // Furnace
3334                         if(!found)
3335                         {
3336                                 ItemSpec specs[9];
3337                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3338                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3339                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3340                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3341                                 specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3342                                 specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3343                                 specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3344                                 specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3345                                 if(checkItemCombination(items, specs))
3346                                 {
3347                                         rlist->addItem(new MaterialItem(CONTENT_FURNACE, 1));
3348                                         found = true;
3349                                 }
3350                         }
3351
3352                         // Steel block
3353                         if(!found)
3354                         {
3355                                 ItemSpec specs[9];
3356                                 specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3357                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3358                                 specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3359                                 specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3360                                 specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3361                                 specs[5] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3362                                 specs[6] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3363                                 specs[7] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3364                                 specs[8] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3365                                 if(checkItemCombination(items, specs))
3366                                 {
3367                                         rlist->addItem(new MaterialItem(CONTENT_STEEL, 1));
3368                                         found = true;
3369                                 }
3370                         }
3371                 }
3372         
3373         } // if creative_mode == false
3374
3375         /*
3376                 Serialize it
3377         */
3378
3379         std::ostringstream os;
3380         //os.imbue(std::locale("C"));
3381
3382         player->inventory.serialize(os);
3383
3384         std::string s = os.str();
3385         
3386         SharedBuffer<u8> data(s.size()+2);
3387         writeU16(&data[0], TOCLIENT_INVENTORY);
3388         memcpy(&data[2], s.c_str(), s.size());
3389         
3390         // Send as reliable
3391         m_con.Send(peer_id, 0, data, true);
3392 }
3393
3394 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3395 {
3396         DSTACK(__FUNCTION_NAME);
3397         
3398         std::ostringstream os(std::ios_base::binary);
3399         u8 buf[12];
3400         
3401         // Write command
3402         writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3403         os.write((char*)buf, 2);
3404         
3405         // Write length
3406         writeU16(buf, message.size());
3407         os.write((char*)buf, 2);
3408         
3409         // Write string
3410         for(u32 i=0; i<message.size(); i++)
3411         {
3412                 u16 w = message[i];
3413                 writeU16(buf, w);
3414                 os.write((char*)buf, 2);
3415         }
3416         
3417         // Make data buffer
3418         std::string s = os.str();
3419         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3420         // Send as reliable
3421         m_con.Send(peer_id, 0, data, true);
3422 }
3423
3424 void Server::BroadcastChatMessage(const std::wstring &message)
3425 {
3426         for(core::map<u16, RemoteClient*>::Iterator
3427                 i = m_clients.getIterator();
3428                 i.atEnd() == false; i++)
3429         {
3430                 // Get client and check that it is valid
3431                 RemoteClient *client = i.getNode()->getValue();
3432                 assert(client->peer_id == i.getNode()->getKey());
3433                 if(client->serialization_version == SER_FMT_VER_INVALID)
3434                         continue;
3435
3436                 SendChatMessage(client->peer_id, message);
3437         }
3438 }
3439
3440 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3441         core::list<u16> *far_players, float far_d_nodes)
3442 {
3443         float maxd = far_d_nodes*BS;
3444         v3f p_f = intToFloat(p, BS);
3445
3446         // Create packet
3447         u32 replysize = 8;
3448         SharedBuffer<u8> reply(replysize);
3449         writeU16(&reply[0], TOCLIENT_REMOVENODE);
3450         writeS16(&reply[2], p.X);
3451         writeS16(&reply[4], p.Y);
3452         writeS16(&reply[6], p.Z);
3453
3454         for(core::map<u16, RemoteClient*>::Iterator
3455                 i = m_clients.getIterator();
3456                 i.atEnd() == false; i++)
3457         {
3458                 // Get client and check that it is valid
3459                 RemoteClient *client = i.getNode()->getValue();
3460                 assert(client->peer_id == i.getNode()->getKey());
3461                 if(client->serialization_version == SER_FMT_VER_INVALID)
3462                         continue;
3463
3464                 // Don't send if it's the same one
3465                 if(client->peer_id == ignore_id)
3466                         continue;
3467                 
3468                 if(far_players)
3469                 {
3470                         // Get player
3471                         Player *player = m_env.getPlayer(client->peer_id);
3472                         if(player)
3473                         {
3474                                 // If player is far away, only set modified blocks not sent
3475                                 v3f player_pos = player->getPosition();
3476                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3477                                 {
3478                                         far_players->push_back(client->peer_id);
3479                                         continue;
3480                                 }
3481                         }
3482                 }
3483
3484                 // Send as reliable
3485                 m_con.Send(client->peer_id, 0, reply, true);
3486         }
3487 }
3488
3489 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3490                 core::list<u16> *far_players, float far_d_nodes)
3491 {
3492         float maxd = far_d_nodes*BS;
3493         v3f p_f = intToFloat(p, BS);
3494
3495         for(core::map<u16, RemoteClient*>::Iterator
3496                 i = m_clients.getIterator();
3497                 i.atEnd() == false; i++)
3498         {
3499                 // Get client and check that it is valid
3500                 RemoteClient *client = i.getNode()->getValue();
3501                 assert(client->peer_id == i.getNode()->getKey());
3502                 if(client->serialization_version == SER_FMT_VER_INVALID)
3503                         continue;
3504
3505                 // Don't send if it's the same one
3506                 if(client->peer_id == ignore_id)
3507                         continue;
3508
3509                 if(far_players)
3510                 {
3511                         // Get player
3512                         Player *player = m_env.getPlayer(client->peer_id);
3513                         if(player)
3514                         {
3515                                 // If player is far away, only set modified blocks not sent
3516                                 v3f player_pos = player->getPosition();
3517                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3518                                 {
3519                                         far_players->push_back(client->peer_id);
3520                                         continue;
3521                                 }
3522                         }
3523                 }
3524
3525                 // Create packet
3526                 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3527                 SharedBuffer<u8> reply(replysize);
3528                 writeU16(&reply[0], TOCLIENT_ADDNODE);
3529                 writeS16(&reply[2], p.X);
3530                 writeS16(&reply[4], p.Y);
3531                 writeS16(&reply[6], p.Z);
3532                 n.serialize(&reply[8], client->serialization_version);
3533
3534                 // Send as reliable
3535                 m_con.Send(client->peer_id, 0, reply, true);
3536         }
3537 }
3538
3539 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3540 {
3541         DSTACK(__FUNCTION_NAME);
3542         /*
3543                 Create a packet with the block in the right format
3544         */
3545         
3546         std::ostringstream os(std::ios_base::binary);
3547         block->serialize(os, ver);
3548         std::string s = os.str();
3549         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3550
3551         u32 replysize = 8 + blockdata.getSize();
3552         SharedBuffer<u8> reply(replysize);
3553         v3s16 p = block->getPos();
3554         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3555         writeS16(&reply[2], p.X);
3556         writeS16(&reply[4], p.Y);
3557         writeS16(&reply[6], p.Z);
3558         memcpy(&reply[8], *blockdata, blockdata.getSize());
3559
3560         /*dstream<<"Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3561                         <<":  \tpacket size: "<<replysize<<std::endl;*/
3562         
3563         /*
3564                 Send packet
3565         */
3566         m_con.Send(peer_id, 1, reply, true);
3567 }
3568
3569 void Server::SendBlocks(float dtime)
3570 {
3571         DSTACK(__FUNCTION_NAME);
3572
3573         JMutexAutoLock envlock(m_env_mutex);
3574         JMutexAutoLock conlock(m_con_mutex);
3575
3576         //TimeTaker timer("Server::SendBlocks");
3577
3578         core::array<PrioritySortedBlockTransfer> queue;
3579
3580         s32 total_sending = 0;
3581
3582         for(core::map<u16, RemoteClient*>::Iterator
3583                 i = m_clients.getIterator();
3584                 i.atEnd() == false; i++)
3585         {
3586                 RemoteClient *client = i.getNode()->getValue();
3587                 assert(client->peer_id == i.getNode()->getKey());
3588
3589                 total_sending += client->SendingCount();
3590                 
3591                 if(client->serialization_version == SER_FMT_VER_INVALID)
3592                         continue;
3593                 
3594                 client->GetNextBlocks(this, dtime, queue);
3595         }
3596
3597         // Sort.
3598         // Lowest priority number comes first.
3599         // Lowest is most important.
3600         queue.sort();
3601
3602         for(u32 i=0; i<queue.size(); i++)
3603         {
3604                 //TODO: Calculate limit dynamically
3605                 if(total_sending >= g_settings.getS32
3606                                 ("max_simultaneous_block_sends_server_total"))
3607                         break;
3608                 
3609                 PrioritySortedBlockTransfer q = queue[i];
3610
3611                 MapBlock *block = NULL;
3612                 try
3613                 {
3614                         block = m_env.getMap().getBlockNoCreate(q.pos);
3615                 }
3616                 catch(InvalidPositionException &e)
3617                 {
3618                         continue;
3619                 }
3620
3621                 RemoteClient *client = getClient(q.peer_id);
3622
3623                 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3624
3625                 client->SentBlock(q.pos);
3626
3627                 total_sending++;
3628         }
3629 }
3630
3631
3632 RemoteClient* Server::getClient(u16 peer_id)
3633 {
3634         DSTACK(__FUNCTION_NAME);
3635         //JMutexAutoLock lock(m_con_mutex);
3636         core::map<u16, RemoteClient*>::Node *n;
3637         n = m_clients.find(peer_id);
3638         // A client should exist for all peers
3639         assert(n != NULL);
3640         return n->getValue();
3641 }
3642
3643 std::wstring Server::getStatusString()
3644 {
3645         std::wostringstream os(std::ios_base::binary);
3646         os<<L"# Server: ";
3647         // Uptime
3648         os<<L"uptime="<<m_uptime.get();
3649         // Information about clients
3650         os<<L", clients={";
3651         for(core::map<u16, RemoteClient*>::Iterator
3652                 i = m_clients.getIterator();
3653                 i.atEnd() == false; i++)
3654         {
3655                 // Get client and check that it is valid
3656                 RemoteClient *client = i.getNode()->getValue();
3657                 assert(client->peer_id == i.getNode()->getKey());
3658                 if(client->serialization_version == SER_FMT_VER_INVALID)
3659                         continue;
3660                 // Get player
3661                 Player *player = m_env.getPlayer(client->peer_id);
3662                 // Get name of player
3663                 std::wstring name = L"unknown";
3664                 if(player != NULL)
3665                         name = narrow_to_wide(player->getName());
3666                 // Add name to information string
3667                 os<<name<<L",";
3668         }
3669         os<<L"}";
3670         if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
3671                 os<<" WARNING: Map saving is disabled."<<std::endl;
3672         return os.str();
3673 }
3674
3675
3676 void setCreativeInventory(Player *player)
3677 {
3678         player->resetInventory();
3679         
3680         // Give some good picks
3681         {
3682                 InventoryItem *item = new ToolItem("STPick", 0);
3683                 void* r = player->inventory.addItem("main", item);
3684                 assert(r == NULL);
3685         }
3686         {
3687                 InventoryItem *item = new ToolItem("MesePick", 0);
3688                 void* r = player->inventory.addItem("main", item);
3689                 assert(r == NULL);
3690         }
3691
3692         /*
3693                 Give materials
3694         */
3695         
3696         // CONTENT_IGNORE-terminated list
3697         u8 material_items[] = {
3698                 CONTENT_TORCH,
3699                 CONTENT_COBBLE,
3700                 CONTENT_MUD,
3701                 CONTENT_STONE,
3702                 CONTENT_SAND,
3703                 CONTENT_TREE,
3704                 CONTENT_LEAVES,
3705                 CONTENT_MESE,
3706                 CONTENT_WATERSOURCE,
3707                 CONTENT_CLOUD,
3708                 CONTENT_CHEST,
3709                 CONTENT_FURNACE,
3710                 CONTENT_SIGN_WALL,
3711                 CONTENT_IGNORE
3712         };
3713         
3714         u8 *mip = material_items;
3715         for(u16 i=0; i<PLAYER_INVENTORY_SIZE; i++)
3716         {
3717                 if(*mip == CONTENT_IGNORE)
3718                         break;
3719
3720                 InventoryItem *item = new MaterialItem(*mip, 1);
3721                 player->inventory.addItem("main", item);
3722
3723                 mip++;
3724         }
3725
3726 #if 0
3727         assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
3728         
3729         // add torch first
3730         InventoryItem *item = new MaterialItem(CONTENT_TORCH, 1);
3731         player->inventory.addItem("main", item);
3732         
3733         // Then others
3734         for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
3735         {
3736                 // Skip some materials
3737                 if(i == CONTENT_WATER || i == CONTENT_TORCH
3738                         || i == CONTENT_COALSTONE)
3739                         continue;
3740
3741                 InventoryItem *item = new MaterialItem(i, 1);
3742                 player->inventory.addItem("main", item);
3743         }
3744 #endif
3745
3746         /*// Sign
3747         {
3748                 InventoryItem *item = new MapBlockObjectItem("Sign Example text");
3749                 void* r = player->inventory.addItem("main", item);
3750                 assert(r == NULL);
3751         }*/
3752 }
3753
3754 Player *Server::emergePlayer(const char *name, const char *password,
3755                 u16 peer_id)
3756 {
3757         /*
3758                 Try to get an existing player
3759         */
3760         Player *player = m_env.getPlayer(name);
3761         if(player != NULL)
3762         {
3763                 // If player is already connected, cancel
3764                 if(player->peer_id != 0)
3765                 {
3766                         dstream<<"emergePlayer(): Player already connected"<<std::endl;
3767                         return NULL;
3768                 }
3769
3770                 // Got one.
3771                 player->peer_id = peer_id;
3772                 
3773                 // Reset inventory to creative if in creative mode
3774                 if(g_settings.getBool("creative_mode"))
3775                 {
3776                         setCreativeInventory(player);
3777                 }
3778
3779                 return player;
3780         }
3781
3782         /*
3783                 If player with the wanted peer_id already exists, cancel.
3784         */
3785         if(m_env.getPlayer(peer_id) != NULL)
3786         {
3787                 dstream<<"emergePlayer(): Player with wrong name but same"
3788                                 " peer_id already exists"<<std::endl;
3789                 return NULL;
3790         }
3791         
3792         /*
3793                 Create a new player
3794         */
3795         {
3796                 player = new ServerRemotePlayer();
3797                 //player->peer_id = c.peer_id;
3798                 //player->peer_id = PEER_ID_INEXISTENT;
3799                 player->peer_id = peer_id;
3800                 player->updateName(name);
3801
3802                 /*
3803                         Set player position
3804                 */
3805                 
3806                 dstream<<"Server: Finding spawn place for player \""
3807                                 <<player->getName()<<"\""<<std::endl;
3808
3809                 v2s16 nodepos;
3810 #if 0
3811                 player->setPosition(intToFloat(v3s16(
3812                                 0,
3813                                 45, //64,
3814                                 0
3815                 ), BS));
3816 #endif
3817 #if 1
3818                 s16 groundheight = 0;
3819 #if 1
3820                 // Try to find a good place a few times
3821                 for(s32 i=0; i<1000; i++)
3822                 {
3823                         s32 range = 1 + i;
3824                         // We're going to try to throw the player to this position
3825                         nodepos = v2s16(-range + (myrand()%(range*2)),
3826                                         -range + (myrand()%(range*2)));
3827                         v2s16 sectorpos = getNodeSectorPos(nodepos);
3828                         // Get sector (NOTE: Don't get because it's slow)
3829                         //m_env.getMap().emergeSector(sectorpos);
3830                         // Get ground height at point (fallbacks to heightmap function)
3831                         groundheight = m_env.getServerMap().findGroundLevel(nodepos);
3832                         // Don't go underwater
3833                         if(groundheight < WATER_LEVEL)
3834                         {
3835                                 //dstream<<"-> Underwater"<<std::endl;
3836                                 continue;
3837                         }
3838                         // Don't go to high places
3839                         if(groundheight > WATER_LEVEL + 4)
3840                         {
3841                                 //dstream<<"-> Underwater"<<std::endl;
3842                                 continue;
3843                         }
3844
3845                         // Found a good place
3846                         dstream<<"Searched through "<<i<<" places."<<std::endl;
3847                         break;
3848                 }
3849 #endif
3850                 
3851                 // If no suitable place was not found, go above water at least.
3852                 if(groundheight < WATER_LEVEL)
3853                         groundheight = WATER_LEVEL;
3854
3855                 player->setPosition(intToFloat(v3s16(
3856                                 nodepos.X,
3857                                 groundheight + 5, // Accomodate mud
3858                                 nodepos.Y
3859                 ), BS));
3860 #endif
3861
3862                 /*
3863                         Add player to environment
3864                 */
3865
3866                 m_env.addPlayer(player);
3867
3868                 /*
3869                         Add stuff to inventory
3870                 */
3871                 
3872                 if(g_settings.getBool("creative_mode"))
3873                 {
3874                         setCreativeInventory(player);
3875                 }
3876                 else
3877                 {
3878                         /*{
3879                                 InventoryItem *item = new ToolItem("WPick", 32000);
3880                                 void* r = player->inventory.addItem("main", item);
3881                                 assert(r == NULL);
3882                         }*/
3883                         /*{
3884                                 InventoryItem *item = new MaterialItem(CONTENT_MESE, 6);
3885                                 void* r = player->inventory.addItem("main", item);
3886                                 assert(r == NULL);
3887                         }
3888                         {
3889                                 InventoryItem *item = new MaterialItem(CONTENT_COALSTONE, 6);
3890                                 void* r = player->inventory.addItem("main", item);
3891                                 assert(r == NULL);
3892                         }
3893                         {
3894                                 InventoryItem *item = new MaterialItem(CONTENT_WOOD, 6);
3895                                 void* r = player->inventory.addItem("main", item);
3896                                 assert(r == NULL);
3897                         }
3898                         {
3899                                 InventoryItem *item = new CraftItem("Stick", 4);
3900                                 void* r = player->inventory.addItem("main", item);
3901                                 assert(r == NULL);
3902                         }
3903                         {
3904                                 InventoryItem *item = new ToolItem("WPick", 32000);
3905                                 void* r = player->inventory.addItem("main", item);
3906                                 assert(r == NULL);
3907                         }
3908                         {
3909                                 InventoryItem *item = new ToolItem("STPick", 32000);
3910                                 void* r = player->inventory.addItem("main", item);
3911                                 assert(r == NULL);
3912                         }*/
3913                         /*// Give some lights
3914                         {
3915                                 InventoryItem *item = new MaterialItem(CONTENT_TORCH, 999);
3916                                 bool r = player->inventory.addItem("main", item);
3917                                 assert(r == true);
3918                         }
3919                         // and some signs
3920                         for(u16 i=0; i<4; i++)
3921                         {
3922                                 InventoryItem *item = new MapBlockObjectItem("Sign Example text");
3923                                 bool r = player->inventory.addItem("main", item);
3924                                 assert(r == true);
3925                         }*/
3926                         /*// Give some other stuff
3927                         {
3928                                 InventoryItem *item = new MaterialItem(CONTENT_TREE, 999);
3929                                 bool r = player->inventory.addItem("main", item);
3930                                 assert(r == true);
3931                         }*/
3932                 }
3933
3934                 return player;
3935                 
3936         } // create new player
3937 }
3938
3939 void Server::handlePeerChange(PeerChange &c)
3940 {
3941         JMutexAutoLock envlock(m_env_mutex);
3942         JMutexAutoLock conlock(m_con_mutex);
3943         
3944         if(c.type == PEER_ADDED)
3945         {
3946                 /*
3947                         Add
3948                 */
3949
3950                 // Error check
3951                 core::map<u16, RemoteClient*>::Node *n;
3952                 n = m_clients.find(c.peer_id);
3953                 // The client shouldn't already exist
3954                 assert(n == NULL);
3955
3956                 // Create client
3957                 RemoteClient *client = new RemoteClient();
3958                 client->peer_id = c.peer_id;
3959                 m_clients.insert(client->peer_id, client);
3960
3961         } // PEER_ADDED
3962         else if(c.type == PEER_REMOVED)
3963         {
3964                 /*
3965                         Delete
3966                 */
3967
3968                 // Error check
3969                 core::map<u16, RemoteClient*>::Node *n;
3970                 n = m_clients.find(c.peer_id);
3971                 // The client should exist
3972                 assert(n != NULL);
3973                 
3974                 // Collect information about leaving in chat
3975                 std::wstring message;
3976                 {
3977                         std::wstring name = L"unknown";
3978                         Player *player = m_env.getPlayer(c.peer_id);
3979                         if(player != NULL)
3980                                 name = narrow_to_wide(player->getName());
3981                         
3982                         message += L"*** ";
3983                         message += name;
3984                         message += L" left game";
3985                         if(c.timeout)
3986                                 message += L" (timed out)";
3987                 }
3988
3989                 /*// Delete player
3990                 {
3991                         m_env.removePlayer(c.peer_id);
3992                 }*/
3993
3994                 // Set player client disconnected
3995                 {
3996                         Player *player = m_env.getPlayer(c.peer_id);
3997                         if(player != NULL)
3998                                 player->peer_id = 0;
3999                 }
4000                 
4001                 // Delete client
4002                 delete m_clients[c.peer_id];
4003                 m_clients.remove(c.peer_id);
4004
4005                 // Send player info to all remaining clients
4006                 SendPlayerInfos();
4007                 
4008                 // Send leave chat message to all remaining clients
4009                 BroadcastChatMessage(message);
4010                 
4011         } // PEER_REMOVED
4012         else
4013         {
4014                 assert(0);
4015         }
4016 }
4017
4018 void Server::handlePeerChanges()
4019 {
4020         while(m_peer_change_queue.size() > 0)
4021         {
4022                 PeerChange c = m_peer_change_queue.pop_front();
4023
4024                 dout_server<<"Server: Handling peer change: "
4025                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4026                                 <<std::endl;
4027
4028                 handlePeerChange(c);
4029         }
4030 }
4031
4032 void dedicated_server_loop(Server &server, bool &kill)
4033 {
4034         DSTACK(__FUNCTION_NAME);
4035         
4036         std::cout<<DTIME<<std::endl;
4037         std::cout<<"========================"<<std::endl;
4038         std::cout<<"Running dedicated server"<<std::endl;
4039         std::cout<<"========================"<<std::endl;
4040         std::cout<<std::endl;
4041
4042         for(;;)
4043         {
4044                 // This is kind of a hack but can be done like this
4045                 // because server.step() is very light
4046                 sleep_ms(30);
4047                 server.step(0.030);
4048
4049                 if(server.getShutdownRequested() || kill)
4050                 {
4051                         std::cout<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4052                         break;
4053                 }
4054
4055                 static int counter = 0;
4056                 counter--;
4057                 if(counter <= 0)
4058                 {
4059                         counter = 10;
4060
4061                         core::list<PlayerInfo> list = server.getPlayerInfo();
4062                         core::list<PlayerInfo>::Iterator i;
4063                         static u32 sum_old = 0;
4064                         u32 sum = PIChecksum(list);
4065                         if(sum != sum_old)
4066                         {
4067                                 std::cout<<DTIME<<"Player info:"<<std::endl;
4068                                 for(i=list.begin(); i!=list.end(); i++)
4069                                 {
4070                                         i->PrintLine(&std::cout);
4071                                 }
4072                         }
4073                         sum_old = sum;
4074                 }
4075         }
4076 }
4077
4078