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