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