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