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