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