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