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