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