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