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