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