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