383381c9fc824f4dfe6ec28fd418f6ff6e71024c
[oweals/minetest.git] / src / server.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "server.h"
21 #include "utility.h"
22 #include <iostream>
23 #include "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. Banned name was "
1936                                 +narrow_to_wide(m_banmanager.getBanName(
1937                                         peer->address.serializeString())));
1938                 m_con.deletePeer(peer_id, false);
1939                 return;
1940         }
1941         
1942         u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1943
1944         try
1945         {
1946
1947         if(datasize < 2)
1948                 return;
1949
1950         ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1951         
1952         if(command == TOSERVER_INIT)
1953         {
1954                 // [0] u16 TOSERVER_INIT
1955                 // [2] u8 SER_FMT_VER_HIGHEST
1956                 // [3] u8[20] player_name
1957                 // [23] u8[28] password <--- can be sent without this, from old versions
1958
1959                 if(datasize < 2+1+PLAYERNAME_SIZE)
1960                         return;
1961
1962                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1963                                 <<peer->id<<std::endl;
1964
1965                 // First byte after command is maximum supported
1966                 // serialization version
1967                 u8 client_max = data[2];
1968                 u8 our_max = SER_FMT_VER_HIGHEST;
1969                 // Use the highest version supported by both
1970                 u8 deployed = core::min_(client_max, our_max);
1971                 // If it's lower than the lowest supported, give up.
1972                 if(deployed < SER_FMT_VER_LOWEST)
1973                         deployed = SER_FMT_VER_INVALID;
1974
1975                 //peer->serialization_version = deployed;
1976                 getClient(peer->id)->pending_serialization_version = deployed;
1977                 
1978                 if(deployed == SER_FMT_VER_INVALID)
1979                 {
1980                         derr_server<<DTIME<<"Server: Cannot negotiate "
1981                                         "serialization version with peer "
1982                                         <<peer_id<<std::endl;
1983                         SendAccessDenied(m_con, peer_id,
1984                                         L"Your client is too old (map format)");
1985                         return;
1986                 }
1987                 
1988                 /*
1989                         Read and check network protocol version
1990                 */
1991
1992                 u16 net_proto_version = 0;
1993                 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1994                 {
1995                         net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1996                 }
1997
1998                 getClient(peer->id)->net_proto_version = net_proto_version;
1999
2000                 if(net_proto_version == 0)
2001                 {
2002                         SendAccessDenied(m_con, peer_id,
2003                                         L"Your client is too old. Please upgrade.");
2004                         return;
2005                 }
2006
2007                 /*
2008                         Set up player
2009                 */
2010                 
2011                 // Get player name
2012                 char playername[PLAYERNAME_SIZE];
2013                 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2014                 {
2015                         playername[i] = data[3+i];
2016                 }
2017                 playername[PLAYERNAME_SIZE-1] = 0;
2018                 
2019                 if(playername[0]=='\0')
2020                 {
2021                         derr_server<<DTIME<<"Server: Player has empty name"<<std::endl;
2022                         SendAccessDenied(m_con, peer_id,
2023                                         L"Empty name");
2024                         return;
2025                 }
2026
2027                 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2028                 {
2029                         derr_server<<DTIME<<"Server: Player has invalid name"<<std::endl;
2030                         SendAccessDenied(m_con, peer_id,
2031                                         L"Name contains unallowed characters");
2032                         return;
2033                 }
2034
2035                 // Get password
2036                 char password[PASSWORD_SIZE];
2037                 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2038                 {
2039                         // old version - assume blank password
2040                         password[0] = 0;
2041                 }
2042                 else
2043                 {
2044                                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2045                                 {
2046                                         password[i] = data[23+i];
2047                                 }
2048                                 password[PASSWORD_SIZE-1] = 0;
2049                 }
2050                 
2051                 std::string checkpwd;
2052                 if(m_authmanager.exists(playername))
2053                 {
2054                         checkpwd = m_authmanager.getPassword(playername);
2055                 }
2056                 else
2057                 {
2058                         checkpwd = g_settings.get("default_password");
2059                 }
2060                 
2061                 /*dstream<<"Server: Client gave password '"<<password
2062                                 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2063                 
2064                 if(password != checkpwd && m_authmanager.exists(playername))
2065                 {
2066                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
2067                                         <<": supplied invalid password for "
2068                                         <<playername<<std::endl;
2069                         SendAccessDenied(m_con, peer_id, L"Invalid password");
2070                         return;
2071                 }
2072                 
2073                 // Add player to auth manager
2074                 if(m_authmanager.exists(playername) == false)
2075                 {
2076                         derr_server<<DTIME<<"Server: adding player "<<playername
2077                                         <<" to auth manager"<<std::endl;
2078                         m_authmanager.add(playername);
2079                         m_authmanager.setPassword(playername, checkpwd);
2080                         m_authmanager.setPrivs(playername,
2081                                         stringToPrivs(g_settings.get("default_privs")));
2082                         m_authmanager.save();
2083                 }
2084
2085                 // Get player
2086                 Player *player = emergePlayer(playername, password, peer_id);
2087
2088
2089                 /*{
2090                         // DEBUG: Test serialization
2091                         std::ostringstream test_os;
2092                         player->serialize(test_os);
2093                         dstream<<"Player serialization test: \""<<test_os.str()
2094                                         <<"\""<<std::endl;
2095                         std::istringstream test_is(test_os.str());
2096                         player->deSerialize(test_is);
2097                 }*/
2098
2099                 // If failed, cancel
2100                 if(player == NULL)
2101                 {
2102                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
2103                                         <<": failed to emerge player"<<std::endl;
2104                         return;
2105                 }
2106
2107                 /*
2108                 // If a client is already connected to the player, cancel
2109                 if(player->peer_id != 0)
2110                 {
2111                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
2112                                         <<" tried to connect to "
2113                                         "an already connected player (peer_id="
2114                                         <<player->peer_id<<")"<<std::endl;
2115                         return;
2116                 }
2117                 // Set client of player
2118                 player->peer_id = peer_id;
2119                 */
2120
2121                 // Check if player doesn't exist
2122                 if(player == NULL)
2123                         throw con::InvalidIncomingDataException
2124                                 ("Server::ProcessData(): INIT: Player doesn't exist");
2125
2126                 /*// update name if it was supplied
2127                 if(datasize >= 20+3)
2128                 {
2129                         data[20+3-1] = 0;
2130                         player->updateName((const char*)&data[3]);
2131                 }*/
2132                 
2133                 /*
2134                         Answer with a TOCLIENT_INIT
2135                 */
2136                 {
2137                         SharedBuffer<u8> reply(2+1+6+8);
2138                         writeU16(&reply[0], TOCLIENT_INIT);
2139                         writeU8(&reply[2], deployed);
2140                         writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2141                         writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
2142                         
2143                         // Send as reliable
2144                         m_con.Send(peer_id, 0, reply, true);
2145                 }
2146
2147                 /*
2148                         Send complete position information
2149                 */
2150                 SendMovePlayer(player);
2151
2152                 return;
2153         }
2154
2155         if(command == TOSERVER_INIT2)
2156         {
2157                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
2158                                 <<peer->id<<std::endl;
2159
2160
2161                 getClient(peer->id)->serialization_version
2162                                 = getClient(peer->id)->pending_serialization_version;
2163
2164                 /*
2165                         Send some initialization data
2166                 */
2167                 
2168                 // Send player info to all players
2169                 SendPlayerInfos();
2170
2171                 // Send inventory to player
2172                 UpdateCrafting(peer->id);
2173                 SendInventory(peer->id);
2174
2175                 // Send player items to all players
2176                 SendPlayerItems();
2177
2178                 // Send HP
2179                 {
2180                         Player *player = m_env.getPlayer(peer_id);
2181                         SendPlayerHP(player);
2182                 }
2183                 
2184                 // Send time of day
2185                 {
2186                         SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2187                                         m_env.getTimeOfDay());
2188                         m_con.Send(peer->id, 0, data, true);
2189                 }
2190                 
2191                 // Send information about server to player in chat
2192                 SendChatMessage(peer_id, getStatusString());
2193                 
2194                 // Send information about joining in chat
2195                 {
2196                         std::wstring name = L"unknown";
2197                         Player *player = m_env.getPlayer(peer_id);
2198                         if(player != NULL)
2199                                 name = narrow_to_wide(player->getName());
2200                         
2201                         std::wstring message;
2202                         message += L"*** ";
2203                         message += name;
2204                         message += L" joined game";
2205                         BroadcastChatMessage(message);
2206                 }
2207                 
2208                 // Warnings about protocol version can be issued here
2209                 /*if(getClient(peer->id)->net_proto_version == 0)
2210                 {
2211                         SendChatMessage(peer_id, L"# Server: NOTE: YOUR CLIENT IS OLD AND DOES NOT WORK PROPERLY WITH THIS SERVER");
2212                 }*/
2213
2214                 return;
2215         }
2216
2217         if(peer_ser_ver == SER_FMT_VER_INVALID)
2218         {
2219                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
2220                                 " serialization format invalid or not initialized."
2221                                 " Skipping incoming command="<<command<<std::endl;
2222                 return;
2223         }
2224         
2225         Player *player = m_env.getPlayer(peer_id);
2226
2227         if(player == NULL){
2228                 derr_server<<"Server::ProcessData(): Cancelling: "
2229                                 "No player for peer_id="<<peer_id
2230                                 <<std::endl;
2231                 return;
2232         }
2233         if(command == TOSERVER_PLAYERPOS)
2234         {
2235                 if(datasize < 2+12+12+4+4)
2236                         return;
2237         
2238                 u32 start = 0;
2239                 v3s32 ps = readV3S32(&data[start+2]);
2240                 v3s32 ss = readV3S32(&data[start+2+12]);
2241                 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2242                 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2243                 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2244                 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2245                 pitch = wrapDegrees(pitch);
2246                 yaw = wrapDegrees(yaw);
2247                 player->setPosition(position);
2248                 player->setSpeed(speed);
2249                 player->setPitch(pitch);
2250                 player->setYaw(yaw);
2251                 
2252                 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2253                                 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2254                                 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2255         }
2256         else if(command == TOSERVER_GOTBLOCKS)
2257         {
2258                 if(datasize < 2+1)
2259                         return;
2260                 
2261                 /*
2262                         [0] u16 command
2263                         [2] u8 count
2264                         [3] v3s16 pos_0
2265                         [3+6] v3s16 pos_1
2266                         ...
2267                 */
2268
2269                 u16 count = data[2];
2270                 for(u16 i=0; i<count; i++)
2271                 {
2272                         if((s16)datasize < 2+1+(i+1)*6)
2273                                 throw con::InvalidIncomingDataException
2274                                         ("GOTBLOCKS length is too short");
2275                         v3s16 p = readV3S16(&data[2+1+i*6]);
2276                         /*dstream<<"Server: GOTBLOCKS ("
2277                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2278                         RemoteClient *client = getClient(peer_id);
2279                         client->GotBlock(p);
2280                 }
2281         }
2282         else if(command == TOSERVER_DELETEDBLOCKS)
2283         {
2284                 if(datasize < 2+1)
2285                         return;
2286                 
2287                 /*
2288                         [0] u16 command
2289                         [2] u8 count
2290                         [3] v3s16 pos_0
2291                         [3+6] v3s16 pos_1
2292                         ...
2293                 */
2294
2295                 u16 count = data[2];
2296                 for(u16 i=0; i<count; i++)
2297                 {
2298                         if((s16)datasize < 2+1+(i+1)*6)
2299                                 throw con::InvalidIncomingDataException
2300                                         ("DELETEDBLOCKS length is too short");
2301                         v3s16 p = readV3S16(&data[2+1+i*6]);
2302                         /*dstream<<"Server: DELETEDBLOCKS ("
2303                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2304                         RemoteClient *client = getClient(peer_id);
2305                         client->SetBlockNotSent(p);
2306                 }
2307         }
2308         else if(command == TOSERVER_CLICK_OBJECT)
2309         {
2310                 if(datasize < 13)
2311                         return;
2312
2313                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2314                         return;
2315
2316                 /*
2317                         [0] u16 command
2318                         [2] u8 button (0=left, 1=right)
2319                         [3] v3s16 block
2320                         [9] s16 id
2321                         [11] u16 item
2322                 */
2323                 u8 button = readU8(&data[2]);
2324                 v3s16 p;
2325                 p.X = readS16(&data[3]);
2326                 p.Y = readS16(&data[5]);
2327                 p.Z = readS16(&data[7]);
2328                 s16 id = readS16(&data[9]);
2329                 //u16 item_i = readU16(&data[11]);
2330
2331                 MapBlock *block = NULL;
2332                 try
2333                 {
2334                         block = m_env.getMap().getBlockNoCreate(p);
2335                 }
2336                 catch(InvalidPositionException &e)
2337                 {
2338                         derr_server<<"CLICK_OBJECT block not found"<<std::endl;
2339                         return;
2340                 }
2341
2342                 MapBlockObject *obj = block->getObject(id);
2343
2344                 if(obj == NULL)
2345                 {
2346                         derr_server<<"CLICK_OBJECT object not found"<<std::endl;
2347                         return;
2348                 }
2349
2350                 //TODO: Check that object is reasonably close
2351                 
2352                 // Left click
2353                 if(button == 0)
2354                 {
2355                         InventoryList *ilist = player->inventory.getList("main");
2356                         if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2357                         {
2358                         
2359                                 // Skip if inventory has no free space
2360                                 if(ilist->getUsedSlots() == ilist->getSize())
2361                                 {
2362                                         dout_server<<"Player inventory has no free space"<<std::endl;
2363                                         return;
2364                                 }
2365                                 
2366                                 /*
2367                                         Create the inventory item
2368                                 */
2369                                 InventoryItem *item = NULL;
2370                                 // If it is an item-object, take the item from it
2371                                 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
2372                                 {
2373                                         item = ((ItemObject*)obj)->createInventoryItem();
2374                                 }
2375                                 // Else create an item of the object
2376                                 else
2377                                 {
2378                                         item = new MapBlockObjectItem
2379                                                         (obj->getInventoryString());
2380                                 }
2381                                 
2382                                 // Add to inventory and send inventory
2383                                 ilist->addItem(item);
2384                                 UpdateCrafting(player->peer_id);
2385                                 SendInventory(player->peer_id);
2386                         }
2387
2388                         // Remove from block
2389                         block->removeObject(id);
2390                 }
2391         }
2392         else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2393         {
2394                 if(datasize < 7)
2395                         return;
2396
2397                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2398                         return;
2399
2400                 /*
2401                         length: 7
2402                         [0] u16 command
2403                         [2] u8 button (0=left, 1=right)
2404                         [3] u16 id
2405                         [5] u16 item
2406                 */
2407                 u8 button = readU8(&data[2]);
2408                 u16 id = readS16(&data[3]);
2409                 u16 item_i = readU16(&data[11]);
2410         
2411                 ServerActiveObject *obj = m_env.getActiveObject(id);
2412
2413                 if(obj == NULL)
2414                 {
2415                         derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2416                                         <<std::endl;
2417                         return;
2418                 }
2419
2420                 // Skip if object has been removed
2421                 if(obj->m_removed)
2422                         return;
2423                 
2424                 //TODO: Check that object is reasonably close
2425                 
2426                 // Left click, pick object up (usually)
2427                 if(button == 0)
2428                 {
2429                         /*
2430                                 Try creating inventory item
2431                         */
2432                         InventoryItem *item = obj->createPickedUpItem();
2433                         
2434                         if(item)
2435                         {
2436                                 InventoryList *ilist = player->inventory.getList("main");
2437                                 if(ilist != NULL)
2438                                 {
2439                                         if(g_settings.getBool("creative_mode") == false)
2440                                         {
2441                                                 // Skip if inventory has no free space
2442                                                 if(ilist->getUsedSlots() == ilist->getSize())
2443                                                 {
2444                                                         dout_server<<"Player inventory has no free space"<<std::endl;
2445                                                         return;
2446                                                 }
2447
2448                                                 // Add to inventory and send inventory
2449                                                 ilist->addItem(item);
2450                                                 UpdateCrafting(player->peer_id);
2451                                                 SendInventory(player->peer_id);
2452                                         }
2453
2454                                         // Remove object from environment
2455                                         obj->m_removed = true;
2456                                 }
2457                         }
2458                         else
2459                         {
2460                                 /*
2461                                         Item cannot be picked up. Punch it instead.
2462                                 */
2463
2464                                 ToolItem *titem = NULL;
2465                                 std::string toolname = "";
2466
2467                                 InventoryList *mlist = player->inventory.getList("main");
2468                                 if(mlist != NULL)
2469                                 {
2470                                         InventoryItem *item = mlist->getItem(item_i);
2471                                         if(item && (std::string)item->getName() == "ToolItem")
2472                                         {
2473                                                 titem = (ToolItem*)item;
2474                                                 toolname = titem->getToolName();
2475                                         }
2476                                 }
2477
2478                                 v3f playerpos = player->getPosition();
2479                                 v3f objpos = obj->getBasePosition();
2480                                 v3f dir = (objpos - playerpos).normalize();
2481                                 
2482                                 u16 wear = obj->punch(toolname, dir);
2483                                 
2484                                 if(titem)
2485                                 {
2486                                         bool weared_out = titem->addWear(wear);
2487                                         if(weared_out)
2488                                                 mlist->deleteItem(item_i);
2489                                         SendInventory(player->peer_id);
2490                                 }
2491                         }
2492                 }
2493                 // Right click, do something with object
2494                 if(button == 1)
2495                 {
2496                         // Track hp changes super-crappily
2497                         u16 oldhp = player->hp;
2498                         
2499                         // Do stuff
2500                         obj->rightClick(player);
2501                         
2502                         // Send back stuff
2503                         if(player->hp != oldhp)
2504                         {
2505                                 SendPlayerHP(player);
2506                         }
2507                 }
2508         }
2509         else if(command == TOSERVER_GROUND_ACTION)
2510         {
2511                 if(datasize < 17)
2512                         return;
2513                 /*
2514                         length: 17
2515                         [0] u16 command
2516                         [2] u8 action
2517                         [3] v3s16 nodepos_undersurface
2518                         [9] v3s16 nodepos_abovesurface
2519                         [15] u16 item
2520                         actions:
2521                         0: start digging
2522                         1: place block
2523                         2: stop digging (all parameters ignored)
2524                         3: digging completed
2525                 */
2526                 u8 action = readU8(&data[2]);
2527                 v3s16 p_under;
2528                 p_under.X = readS16(&data[3]);
2529                 p_under.Y = readS16(&data[5]);
2530                 p_under.Z = readS16(&data[7]);
2531                 v3s16 p_over;
2532                 p_over.X = readS16(&data[9]);
2533                 p_over.Y = readS16(&data[11]);
2534                 p_over.Z = readS16(&data[13]);
2535                 u16 item_i = readU16(&data[15]);
2536
2537                 //TODO: Check that target is reasonably close
2538                 
2539                 /*
2540                         0: start digging
2541                 */
2542                 if(action == 0)
2543                 {
2544                         /*
2545                                 NOTE: This can be used in the future to check if
2546                                 somebody is cheating, by checking the timing.
2547                         */
2548                 } // action == 0
2549
2550                 /*
2551                         2: stop digging
2552                 */
2553                 else if(action == 2)
2554                 {
2555 #if 0
2556                         RemoteClient *client = getClient(peer->id);
2557                         JMutexAutoLock digmutex(client->m_dig_mutex);
2558                         client->m_dig_tool_item = -1;
2559 #endif
2560                 }
2561
2562                 /*
2563                         3: Digging completed
2564                 */
2565                 else if(action == 3)
2566                 {
2567                         // Mandatory parameter; actually used for nothing
2568                         core::map<v3s16, MapBlock*> modified_blocks;
2569
2570                         content_t material = CONTENT_IGNORE;
2571                         u8 mineral = MINERAL_NONE;
2572
2573                         bool cannot_remove_node = false;
2574
2575                         try
2576                         {
2577                                 MapNode n = m_env.getMap().getNode(p_under);
2578                                 // Get mineral
2579                                 mineral = n.getMineral();
2580                                 // Get material at position
2581                                 material = n.getContent();
2582                                 // If not yet cancelled
2583                                 if(cannot_remove_node == false)
2584                                 {
2585                                         // If it's not diggable, do nothing
2586                                         if(content_diggable(material) == false)
2587                                         {
2588                                                 derr_server<<"Server: Not finishing digging: "
2589                                                                 <<"Node not diggable"
2590                                                                 <<std::endl;
2591                                                 cannot_remove_node = true;
2592                                         }
2593                                 }
2594                                 // If not yet cancelled
2595                                 if(cannot_remove_node == false)
2596                                 {
2597                                         // Get node metadata
2598                                         NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2599                                         if(meta && meta->nodeRemovalDisabled() == true)
2600                                         {
2601                                                 derr_server<<"Server: Not finishing digging: "
2602                                                                 <<"Node metadata disables removal"
2603                                                                 <<std::endl;
2604                                                 cannot_remove_node = true;
2605                                         }
2606                                 }
2607                         }
2608                         catch(InvalidPositionException &e)
2609                         {
2610                                 derr_server<<"Server: Not finishing digging: Node not found."
2611                                                 <<" Adding block to emerge queue."
2612                                                 <<std::endl;
2613                                 m_emerge_queue.addBlock(peer_id,
2614                                                 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2615                                 cannot_remove_node = true;
2616                         }
2617
2618                         // Make sure the player is allowed to do it
2619                         if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2620                         {
2621                                 dstream<<"Player "<<player->getName()<<" cannot remove node"
2622                                                 <<" because privileges are "<<getPlayerPrivs(player)
2623                                                 <<std::endl;
2624                                 cannot_remove_node = true;
2625                         }
2626
2627                         /*
2628                                 If node can't be removed, set block to be re-sent to
2629                                 client and quit.
2630                         */
2631                         if(cannot_remove_node)
2632                         {
2633                                 derr_server<<"Server: Not finishing digging."<<std::endl;
2634
2635                                 // Client probably has wrong data.
2636                                 // Set block not sent, so that client will get
2637                                 // a valid one.
2638                                 dstream<<"Client "<<peer_id<<" tried to dig "
2639                                                 <<"node; but node cannot be removed."
2640                                                 <<" setting MapBlock not sent."<<std::endl;
2641                                 RemoteClient *client = getClient(peer_id);
2642                                 v3s16 blockpos = getNodeBlockPos(p_under);
2643                                 client->SetBlockNotSent(blockpos);
2644                                         
2645                                 return;
2646                         }
2647                         
2648                         /*
2649                                 Send the removal to all close-by players.
2650                                 - If other player is close, send REMOVENODE
2651                                 - Otherwise set blocks not sent
2652                         */
2653                         core::list<u16> far_players;
2654                         sendRemoveNode(p_under, peer_id, &far_players, 30);
2655                         
2656                         /*
2657                                 Update and send inventory
2658                         */
2659
2660                         if(g_settings.getBool("creative_mode") == false)
2661                         {
2662                                 /*
2663                                         Wear out tool
2664                                 */
2665                                 InventoryList *mlist = player->inventory.getList("main");
2666                                 if(mlist != NULL)
2667                                 {
2668                                         InventoryItem *item = mlist->getItem(item_i);
2669                                         if(item && (std::string)item->getName() == "ToolItem")
2670                                         {
2671                                                 ToolItem *titem = (ToolItem*)item;
2672                                                 std::string toolname = titem->getToolName();
2673
2674                                                 // Get digging properties for material and tool
2675                                                 DiggingProperties prop =
2676                                                                 getDiggingProperties(material, toolname);
2677
2678                                                 if(prop.diggable == false)
2679                                                 {
2680                                                         derr_server<<"Server: WARNING: Player digged"
2681                                                                         <<" with impossible material + tool"
2682                                                                         <<" combination"<<std::endl;
2683                                                 }
2684                                                 
2685                                                 bool weared_out = titem->addWear(prop.wear);
2686
2687                                                 if(weared_out)
2688                                                 {
2689                                                         mlist->deleteItem(item_i);
2690                                                 }
2691                                         }
2692                                 }
2693
2694                                 /*
2695                                         Add dug item to inventory
2696                                 */
2697
2698                                 InventoryItem *item = NULL;
2699
2700                                 if(mineral != MINERAL_NONE)
2701                                         item = getDiggedMineralItem(mineral);
2702                                 
2703                                 // If not mineral
2704                                 if(item == NULL)
2705                                 {
2706                                         std::string &dug_s = content_features(material).dug_item;
2707                                         if(dug_s != "")
2708                                         {
2709                                                 std::istringstream is(dug_s, std::ios::binary);
2710                                                 item = InventoryItem::deSerialize(is);
2711                                         }
2712                                 }
2713                                 
2714                                 if(item != NULL)
2715                                 {
2716                                         // Add a item to inventory
2717                                         player->inventory.addItem("main", item);
2718
2719                                         // Send inventory
2720                                         UpdateCrafting(player->peer_id);
2721                                         SendInventory(player->peer_id);
2722                                 }
2723                         }
2724
2725                         /*
2726                                 Remove the node
2727                                 (this takes some time so it is done after the quick stuff)
2728                         */
2729                         {
2730                                 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2731
2732                                 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2733                         }
2734                         /*
2735                                 Set blocks not sent to far players
2736                         */
2737                         for(core::list<u16>::Iterator
2738                                         i = far_players.begin();
2739                                         i != far_players.end(); i++)
2740                         {
2741                                 u16 peer_id = *i;
2742                                 RemoteClient *client = getClient(peer_id);
2743                                 if(client==NULL)
2744                                         continue;
2745                                 client->SetBlocksNotSent(modified_blocks);
2746                         }
2747                 }
2748                 
2749                 /*
2750                         1: place block
2751                 */
2752                 else if(action == 1)
2753                 {
2754
2755                         InventoryList *ilist = player->inventory.getList("main");
2756                         if(ilist == NULL)
2757                                 return;
2758
2759                         // Get item
2760                         InventoryItem *item = ilist->getItem(item_i);
2761                         
2762                         // If there is no item, it is not possible to add it anywhere
2763                         if(item == NULL)
2764                                 return;
2765                         
2766                         /*
2767                                 Handle material items
2768                         */
2769                         if(std::string("MaterialItem") == item->getName())
2770                         {
2771                                 try{
2772                                         // Don't add a node if this is not a free space
2773                                         MapNode n2 = m_env.getMap().getNode(p_over);
2774                                         bool no_enough_privs =
2775                                                         ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2776                                         if(no_enough_privs)
2777                                                 dstream<<"Player "<<player->getName()<<" cannot add node"
2778                                                         <<" because privileges are "<<getPlayerPrivs(player)
2779                                                         <<std::endl;
2780
2781                                         if(content_features(n2).buildable_to == false
2782                                                 || no_enough_privs)
2783                                         {
2784                                                 // Client probably has wrong data.
2785                                                 // Set block not sent, so that client will get
2786                                                 // a valid one.
2787                                                 dstream<<"Client "<<peer_id<<" tried to place"
2788                                                                 <<" node in invalid position; setting"
2789                                                                 <<" MapBlock not sent."<<std::endl;
2790                                                 RemoteClient *client = getClient(peer_id);
2791                                                 v3s16 blockpos = getNodeBlockPos(p_over);
2792                                                 client->SetBlockNotSent(blockpos);
2793                                                 return;
2794                                         }
2795                                 }
2796                                 catch(InvalidPositionException &e)
2797                                 {
2798                                         derr_server<<"Server: Ignoring ADDNODE: Node not found"
2799                                                         <<" Adding block to emerge queue."
2800                                                         <<std::endl;
2801                                         m_emerge_queue.addBlock(peer_id,
2802                                                         getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2803                                         return;
2804                                 }
2805
2806                                 // Reset build time counter
2807                                 getClient(peer->id)->m_time_from_building = 0.0;
2808                                 
2809                                 // Create node data
2810                                 MaterialItem *mitem = (MaterialItem*)item;
2811                                 MapNode n;
2812                                 n.setContent(mitem->getMaterial());
2813
2814                                 // Calculate direction for wall mounted stuff
2815                                 if(content_features(n).wall_mounted)
2816                                         n.param2 = packDir(p_under - p_over);
2817
2818                                 // Calculate the direction for furnaces and chests and stuff
2819                                 if(content_features(n).param_type == CPT_FACEDIR_SIMPLE)
2820                                 {
2821                                         v3f playerpos = player->getPosition();
2822                                         v3f blockpos = intToFloat(p_over, BS) - playerpos;
2823                                         blockpos = blockpos.normalize();
2824                                         n.param1 = 0;
2825                                         if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2826                                                 if (blockpos.X < 0)
2827                                                         n.param1 = 3;
2828                                                 else
2829                                                         n.param1 = 1;
2830                                         } else {
2831                                                 if (blockpos.Z < 0)
2832                                                         n.param1 = 2;
2833                                                 else
2834                                                         n.param1 = 0;
2835                                         }
2836                                 }
2837
2838                                 /*
2839                                         Send to all close-by players
2840                                 */
2841                                 core::list<u16> far_players;
2842                                 sendAddNode(p_over, n, 0, &far_players, 30);
2843                                 
2844                                 /*
2845                                         Handle inventory
2846                                 */
2847                                 InventoryList *ilist = player->inventory.getList("main");
2848                                 if(g_settings.getBool("creative_mode") == false && ilist)
2849                                 {
2850                                         // Remove from inventory and send inventory
2851                                         if(mitem->getCount() == 1)
2852                                                 ilist->deleteItem(item_i);
2853                                         else
2854                                                 mitem->remove(1);
2855                                         // Send inventory
2856                                         UpdateCrafting(peer_id);
2857                                         SendInventory(peer_id);
2858                                 }
2859                                 
2860                                 /*
2861                                         Add node.
2862
2863                                         This takes some time so it is done after the quick stuff
2864                                 */
2865                                 core::map<v3s16, MapBlock*> modified_blocks;
2866                                 {
2867                                         MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2868
2869                                         m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2870                                 }
2871                                 /*
2872                                         Set blocks not sent to far players
2873                                 */
2874                                 for(core::list<u16>::Iterator
2875                                                 i = far_players.begin();
2876                                                 i != far_players.end(); i++)
2877                                 {
2878                                         u16 peer_id = *i;
2879                                         RemoteClient *client = getClient(peer_id);
2880                                         if(client==NULL)
2881                                                 continue;
2882                                         client->SetBlocksNotSent(modified_blocks);
2883                                 }
2884
2885                                 /*
2886                                         Calculate special events
2887                                 */
2888                                 
2889                                 /*if(n.d == CONTENT_MESE)
2890                                 {
2891                                         u32 count = 0;
2892                                         for(s16 z=-1; z<=1; z++)
2893                                         for(s16 y=-1; y<=1; y++)
2894                                         for(s16 x=-1; x<=1; x++)
2895                                         {
2896                                                 
2897                                         }
2898                                 }*/
2899                         }
2900                         /*
2901                                 Place other item (not a block)
2902                         */
2903                         else
2904                         {
2905                                 v3s16 blockpos = getNodeBlockPos(p_over);
2906                                 
2907                                 /*
2908                                         Check that the block is loaded so that the item
2909                                         can properly be added to the static list too
2910                                 */
2911                                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2912                                 if(block==NULL)
2913                                 {
2914                                         derr_server<<"Error while placing object: "
2915                                                         "block not found"<<std::endl;
2916                                         return;
2917                                 }
2918
2919                                 dout_server<<"Placing a miscellaneous item on map"
2920                                                 <<std::endl;
2921                                 
2922                                 // Calculate a position for it
2923                                 v3f pos = intToFloat(p_over, BS);
2924                                 //pos.Y -= BS*0.45;
2925                                 pos.Y -= BS*0.25; // let it drop a bit
2926                                 // Randomize a bit
2927                                 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2928                                 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2929
2930                                 /*
2931                                         Create the object
2932                                 */
2933                                 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2934
2935                                 if(obj == NULL)
2936                                 {
2937                                         derr_server<<"WARNING: item resulted in NULL object, "
2938                                                         <<"not placing onto map"
2939                                                         <<std::endl;
2940                                 }
2941                                 else
2942                                 {
2943                                         // Add the object to the environment
2944                                         m_env.addActiveObject(obj);
2945                                         
2946                                         dout_server<<"Placed object"<<std::endl;
2947
2948                                         if(g_settings.getBool("creative_mode") == false)
2949                                         {
2950                                                 // Delete the right amount of items from the slot
2951                                                 u16 dropcount = item->getDropCount();
2952                                                 
2953                                                 // Delete item if all gone
2954                                                 if(item->getCount() <= dropcount)
2955                                                 {
2956                                                         if(item->getCount() < dropcount)
2957                                                                 dstream<<"WARNING: Server: dropped more items"
2958                                                                                 <<" than the slot contains"<<std::endl;
2959                                                         
2960                                                         InventoryList *ilist = player->inventory.getList("main");
2961                                                         if(ilist)
2962                                                                 // Remove from inventory and send inventory
2963                                                                 ilist->deleteItem(item_i);
2964                                                 }
2965                                                 // Else decrement it
2966                                                 else
2967                                                         item->remove(dropcount);
2968                                                 
2969                                                 // Send inventory
2970                                                 UpdateCrafting(peer_id);
2971                                                 SendInventory(peer_id);
2972                                         }
2973                                 }
2974                         }
2975
2976                 } // action == 1
2977
2978                 /*
2979                         Catch invalid actions
2980                 */
2981                 else
2982                 {
2983                         derr_server<<"WARNING: Server: Invalid action "
2984                                         <<action<<std::endl;
2985                 }
2986         }
2987 #if 0
2988         else if(command == TOSERVER_RELEASE)
2989         {
2990                 if(datasize < 3)
2991                         return;
2992                 /*
2993                         length: 3
2994                         [0] u16 command
2995                         [2] u8 button
2996                 */
2997                 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
2998         }
2999 #endif
3000         else if(command == TOSERVER_SIGNTEXT)
3001         {
3002                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3003                         return;
3004                 /*
3005                         u16 command
3006                         v3s16 blockpos
3007                         s16 id
3008                         u16 textlen
3009                         textdata
3010                 */
3011                 std::string datastring((char*)&data[2], datasize-2);
3012                 std::istringstream is(datastring, std::ios_base::binary);
3013                 u8 buf[6];
3014                 // Read stuff
3015                 is.read((char*)buf, 6);
3016                 v3s16 blockpos = readV3S16(buf);
3017                 is.read((char*)buf, 2);
3018                 s16 id = readS16(buf);
3019                 is.read((char*)buf, 2);
3020                 u16 textlen = readU16(buf);
3021                 std::string text;
3022                 for(u16 i=0; i<textlen; i++)
3023                 {
3024                         is.read((char*)buf, 1);
3025                         text += (char)buf[0];
3026                 }
3027
3028                 MapBlock *block = NULL;
3029                 try
3030                 {
3031                         block = m_env.getMap().getBlockNoCreate(blockpos);
3032                 }
3033                 catch(InvalidPositionException &e)
3034                 {
3035                         derr_server<<"Error while setting sign text: "
3036                                         "block not found"<<std::endl;
3037                         return;
3038                 }
3039
3040                 MapBlockObject *obj = block->getObject(id);
3041                 if(obj == NULL)
3042                 {
3043                         derr_server<<"Error while setting sign text: "
3044                                         "object not found"<<std::endl;
3045                         return;
3046                 }
3047                 
3048                 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
3049                 {
3050                         derr_server<<"Error while setting sign text: "
3051                                         "object is not a sign"<<std::endl;
3052                         return;
3053                 }
3054
3055                 ((SignObject*)obj)->setText(text);
3056
3057                 obj->getBlock()->setChangedFlag();
3058         }
3059         else if(command == TOSERVER_SIGNNODETEXT)
3060         {
3061                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3062                         return;
3063                 /*
3064                         u16 command
3065                         v3s16 p
3066                         u16 textlen
3067                         textdata
3068                 */
3069                 std::string datastring((char*)&data[2], datasize-2);
3070                 std::istringstream is(datastring, std::ios_base::binary);
3071                 u8 buf[6];
3072                 // Read stuff
3073                 is.read((char*)buf, 6);
3074                 v3s16 p = readV3S16(buf);
3075                 is.read((char*)buf, 2);
3076                 u16 textlen = readU16(buf);
3077                 std::string text;
3078                 for(u16 i=0; i<textlen; i++)
3079                 {
3080                         is.read((char*)buf, 1);
3081                         text += (char)buf[0];
3082                 }
3083
3084                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3085                 if(!meta)
3086                         return;
3087                 if(meta->typeId() != CONTENT_SIGN_WALL)
3088                         return;
3089                 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
3090                 signmeta->setText(text);
3091                 
3092                 v3s16 blockpos = getNodeBlockPos(p);
3093                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
3094                 if(block)
3095                 {
3096                         block->setChangedFlag();
3097                 }
3098
3099                 for(core::map<u16, RemoteClient*>::Iterator
3100                         i = m_clients.getIterator();
3101                         i.atEnd()==false; i++)
3102                 {
3103                         RemoteClient *client = i.getNode()->getValue();
3104                         client->SetBlockNotSent(blockpos);
3105                 }
3106         }
3107         else if(command == TOSERVER_INVENTORY_ACTION)
3108         {
3109                 /*// Ignore inventory changes if in creative mode
3110                 if(g_settings.getBool("creative_mode") == true)
3111                 {
3112                         dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3113                                         <<std::endl;
3114                         return;
3115                 }*/
3116                 // Strip command and create a stream
3117                 std::string datastring((char*)&data[2], datasize-2);
3118                 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3119                 std::istringstream is(datastring, std::ios_base::binary);
3120                 // Create an action
3121                 InventoryAction *a = InventoryAction::deSerialize(is);
3122                 if(a != NULL)
3123                 {
3124                         // Create context
3125                         InventoryContext c;
3126                         c.current_player = player;
3127
3128                         /*
3129                                 Handle craftresult specially if not in creative mode
3130                         */
3131                         bool disable_action = false;
3132                         if(a->getType() == IACTION_MOVE
3133                                         && g_settings.getBool("creative_mode") == false)
3134                         {
3135                                 IMoveAction *ma = (IMoveAction*)a;
3136                                 if(ma->to_inv == "current_player" &&
3137                                                 ma->from_inv == "current_player")
3138                                 {
3139                                         InventoryList *rlist = player->inventory.getList("craftresult");
3140                                         assert(rlist);
3141                                         InventoryList *clist = player->inventory.getList("craft");
3142                                         assert(clist);
3143                                         InventoryList *mlist = player->inventory.getList("main");
3144                                         assert(mlist);
3145                                         /*
3146                                                 Craftresult is no longer preview if something
3147                                                 is moved into it
3148                                         */
3149                                         if(ma->to_list == "craftresult"
3150                                                         && ma->from_list != "craftresult")
3151                                         {
3152                                                 // If it currently is a preview, remove
3153                                                 // its contents
3154                                                 if(player->craftresult_is_preview)
3155                                                 {
3156                                                         rlist->deleteItem(0);
3157                                                 }
3158                                                 player->craftresult_is_preview = false;
3159                                         }
3160                                         /*
3161                                                 Crafting takes place if this condition is true.
3162                                         */
3163                                         if(player->craftresult_is_preview &&
3164                                                         ma->from_list == "craftresult")
3165                                         {
3166                                                 player->craftresult_is_preview = false;
3167                                                 clist->decrementMaterials(1);
3168                                         }
3169                                         /*
3170                                                 If the craftresult is placed on itself, move it to
3171                                                 main inventory instead of doing the action
3172                                         */
3173                                         if(ma->to_list == "craftresult"
3174                                                         && ma->from_list == "craftresult")
3175                                         {
3176                                                 disable_action = true;
3177                                                 
3178                                                 InventoryItem *item1 = rlist->changeItem(0, NULL);
3179                                                 mlist->addItem(item1);
3180                                         }
3181                                 }
3182                         }
3183                         
3184                         if(disable_action == false)
3185                         {
3186                                 // Feed action to player inventory
3187                                 a->apply(&c, this);
3188                                 // Eat the action
3189                                 delete a;
3190                         }
3191                         else
3192                         {
3193                                 // Send inventory
3194                                 UpdateCrafting(player->peer_id);
3195                                 SendInventory(player->peer_id);
3196                         }
3197                 }
3198                 else
3199                 {
3200                         dstream<<"TOSERVER_INVENTORY_ACTION: "
3201                                         <<"InventoryAction::deSerialize() returned NULL"
3202                                         <<std::endl;
3203                 }
3204         }
3205         else if(command == TOSERVER_CHAT_MESSAGE)
3206         {
3207                 /*
3208                         u16 command
3209                         u16 length
3210                         wstring message
3211                 */
3212                 u8 buf[6];
3213                 std::string datastring((char*)&data[2], datasize-2);
3214                 std::istringstream is(datastring, std::ios_base::binary);
3215                 
3216                 // Read stuff
3217                 is.read((char*)buf, 2);
3218                 u16 len = readU16(buf);
3219                 
3220                 std::wstring message;
3221                 for(u16 i=0; i<len; i++)
3222                 {
3223                         is.read((char*)buf, 2);
3224                         message += (wchar_t)readU16(buf);
3225                 }
3226
3227                 // Get player name of this client
3228                 std::wstring name = narrow_to_wide(player->getName());
3229                 
3230                 // Line to send to players
3231                 std::wstring line;
3232                 // Whether to send to the player that sent the line
3233                 bool send_to_sender = false;
3234                 // Whether to send to other players
3235                 bool send_to_others = false;
3236                 
3237                 // Local player gets all privileges regardless of
3238                 // what's set on their account.
3239                 u64 privs = getPlayerPrivs(player);
3240
3241                 // Parse commands
3242                 std::wstring commandprefix = L"/#";
3243                 if(message.substr(0, commandprefix.size()) == commandprefix)
3244                 {
3245                         line += L"Server: ";
3246
3247                         message = message.substr(commandprefix.size());
3248                         
3249                         WStrfnd f1(message);
3250                         f1.next(L" "); // Skip over /#whatever
3251                         std::wstring paramstring = f1.next(L"");
3252
3253                         ServerCommandContext *ctx = new ServerCommandContext(
3254                                 str_split(message, L' '),
3255                                 paramstring,
3256                                 this,
3257                                 &m_env,
3258                                 player,
3259                                 privs);
3260
3261                         line += processServerCommand(ctx);
3262                         send_to_sender = ctx->flags & 1;
3263                         send_to_others = ctx->flags & 2;
3264                         delete ctx;
3265
3266                 }
3267                 else
3268                 {
3269                         if(privs & PRIV_SHOUT)
3270                         {
3271                                 line += L"<";
3272                                 line += name;
3273                                 line += L"> ";
3274                                 line += message;
3275                                 send_to_others = true;
3276                         }
3277                         else
3278                         {
3279                                 line += L"Server: You are not allowed to shout";
3280                                 send_to_sender = true;
3281                         }
3282                 }
3283                 
3284                 if(line != L"")
3285                 {
3286                         dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3287
3288                         /*
3289                                 Send the message to clients
3290                         */
3291                         for(core::map<u16, RemoteClient*>::Iterator
3292                                 i = m_clients.getIterator();
3293                                 i.atEnd() == false; i++)
3294                         {
3295                                 // Get client and check that it is valid
3296                                 RemoteClient *client = i.getNode()->getValue();
3297                                 assert(client->peer_id == i.getNode()->getKey());
3298                                 if(client->serialization_version == SER_FMT_VER_INVALID)
3299                                         continue;
3300
3301                                 // Filter recipient
3302                                 bool sender_selected = (peer_id == client->peer_id);
3303                                 if(sender_selected == true && send_to_sender == false)
3304                                         continue;
3305                                 if(sender_selected == false && send_to_others == false)
3306                                         continue;
3307
3308                                 SendChatMessage(client->peer_id, line);
3309                         }
3310                 }
3311         }
3312         else if(command == TOSERVER_DAMAGE)
3313         {
3314                 if(g_settings.getBool("enable_damage"))
3315                 {
3316                         std::string datastring((char*)&data[2], datasize-2);
3317                         std::istringstream is(datastring, std::ios_base::binary);
3318                         u8 damage = readU8(is);
3319                         if(player->hp > damage)
3320                         {
3321                                 player->hp -= damage;
3322                         }
3323                         else
3324                         {
3325                                 player->hp = 0;
3326
3327                                 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3328                                                 <<std::endl;
3329                                 
3330                                 v3f pos = findSpawnPos(m_env.getServerMap());
3331                                 player->setPosition(pos);
3332                                 player->hp = 20;
3333                                 SendMovePlayer(player);
3334                                 SendPlayerHP(player);
3335                                 
3336                                 //TODO: Throw items around
3337                         }
3338                 }
3339
3340                 SendPlayerHP(player);
3341         }
3342         else if(command == TOSERVER_PASSWORD)
3343         {
3344                 /*
3345                         [0] u16 TOSERVER_PASSWORD
3346                         [2] u8[28] old password
3347                         [30] u8[28] new password
3348                 */
3349
3350                 if(datasize != 2+PASSWORD_SIZE*2)
3351                         return;
3352                 /*char password[PASSWORD_SIZE];
3353                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3354                         password[i] = data[2+i];
3355                 password[PASSWORD_SIZE-1] = 0;*/
3356                 std::string oldpwd;
3357                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3358                 {
3359                         char c = data[2+i];
3360                         if(c == 0)
3361                                 break;
3362                         oldpwd += c;
3363                 }
3364                 std::string newpwd;
3365                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3366                 {
3367                         char c = data[2+PASSWORD_SIZE+i];
3368                         if(c == 0)
3369                                 break;
3370                         newpwd += c;
3371                 }
3372
3373                 dstream<<"Server: Client requests a password change from "
3374                                 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
3375
3376                 std::string playername = player->getName();
3377
3378                 if(m_authmanager.exists(playername) == false)
3379                 {
3380                         dstream<<"Server: playername not found in authmanager"<<std::endl;
3381                         // Wrong old password supplied!!
3382                         SendChatMessage(peer_id, L"playername not found in authmanager");
3383                         return;
3384                 }
3385
3386                 std::string checkpwd = m_authmanager.getPassword(playername);
3387
3388                 if(oldpwd != checkpwd)
3389                 {
3390                         dstream<<"Server: invalid old password"<<std::endl;
3391                         // Wrong old password supplied!!
3392                         SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3393                         return;
3394                 }
3395
3396                 m_authmanager.setPassword(playername, newpwd);
3397                 
3398                 dstream<<"Server: password change successful for "<<playername
3399                                 <<std::endl;
3400                 SendChatMessage(peer_id, L"Password change successful");
3401         }
3402         else if (command == TOSERVER_PLAYERITEM)
3403         {
3404                 if (datasize < 2+2)
3405                         return;
3406
3407                 u16 item = readU16(&data[2]);
3408                 player->wieldItem(item);
3409                 SendWieldedItem(player);
3410         }
3411         else
3412         {
3413                 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3414                                 "unknown command "<<command<<std::endl;
3415         }
3416         
3417         } //try
3418         catch(SendFailedException &e)
3419         {
3420                 derr_server<<"Server::ProcessData(): SendFailedException: "
3421                                 <<"what="<<e.what()
3422                                 <<std::endl;
3423         }
3424 }
3425
3426 void Server::onMapEditEvent(MapEditEvent *event)
3427 {
3428         //dstream<<"Server::onMapEditEvent()"<<std::endl;
3429         if(m_ignore_map_edit_events)
3430                 return;
3431         MapEditEvent *e = event->clone();
3432         m_unsent_map_edit_queue.push_back(e);
3433 }
3434
3435 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3436 {
3437         if(id == "current_player")
3438         {
3439                 assert(c->current_player);
3440                 return &(c->current_player->inventory);
3441         }
3442         
3443         Strfnd fn(id);
3444         std::string id0 = fn.next(":");
3445
3446         if(id0 == "nodemeta")
3447         {
3448                 v3s16 p;
3449                 p.X = stoi(fn.next(","));
3450                 p.Y = stoi(fn.next(","));
3451                 p.Z = stoi(fn.next(","));
3452                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3453                 if(meta)
3454                         return meta->getInventory();
3455                 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3456                                 <<"no metadata found"<<std::endl;
3457                 return NULL;
3458         }
3459
3460         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3461         return NULL;
3462 }
3463 void Server::inventoryModified(InventoryContext *c, std::string id)
3464 {
3465         if(id == "current_player")
3466         {
3467                 assert(c->current_player);
3468                 // Send inventory
3469                 UpdateCrafting(c->current_player->peer_id);
3470                 SendInventory(c->current_player->peer_id);
3471                 return;
3472         }
3473         
3474         Strfnd fn(id);
3475         std::string id0 = fn.next(":");
3476
3477         if(id0 == "nodemeta")
3478         {
3479                 v3s16 p;
3480                 p.X = stoi(fn.next(","));
3481                 p.Y = stoi(fn.next(","));
3482                 p.Z = stoi(fn.next(","));
3483                 v3s16 blockpos = getNodeBlockPos(p);
3484
3485                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3486                 if(meta)
3487                         meta->inventoryModified();
3488
3489                 for(core::map<u16, RemoteClient*>::Iterator
3490                         i = m_clients.getIterator();
3491                         i.atEnd()==false; i++)
3492                 {
3493                         RemoteClient *client = i.getNode()->getValue();
3494                         client->SetBlockNotSent(blockpos);
3495                 }
3496
3497                 return;
3498         }
3499
3500         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3501 }
3502
3503 core::list<PlayerInfo> Server::getPlayerInfo()
3504 {
3505         DSTACK(__FUNCTION_NAME);
3506         JMutexAutoLock envlock(m_env_mutex);
3507         JMutexAutoLock conlock(m_con_mutex);
3508         
3509         core::list<PlayerInfo> list;
3510
3511         core::list<Player*> players = m_env.getPlayers();
3512         
3513         core::list<Player*>::Iterator i;
3514         for(i = players.begin();
3515                         i != players.end(); i++)
3516         {
3517                 PlayerInfo info;
3518
3519                 Player *player = *i;
3520
3521                 try{
3522                         con::Peer *peer = m_con.GetPeer(player->peer_id);
3523                         // Copy info from peer to info struct
3524                         info.id = peer->id;
3525                         info.address = peer->address;
3526                         info.avg_rtt = peer->avg_rtt;
3527                 }
3528                 catch(con::PeerNotFoundException &e)
3529                 {
3530                         // Set dummy peer info
3531                         info.id = 0;
3532                         info.address = Address(0,0,0,0,0);
3533                         info.avg_rtt = 0.0;
3534                 }
3535
3536                 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3537                 info.position = player->getPosition();
3538
3539                 list.push_back(info);
3540         }
3541
3542         return list;
3543 }
3544
3545
3546 void Server::peerAdded(con::Peer *peer)
3547 {
3548         DSTACK(__FUNCTION_NAME);
3549         dout_server<<"Server::peerAdded(): peer->id="
3550                         <<peer->id<<std::endl;
3551         
3552         PeerChange c;
3553         c.type = PEER_ADDED;
3554         c.peer_id = peer->id;
3555         c.timeout = false;
3556         m_peer_change_queue.push_back(c);
3557 }
3558
3559 void Server::deletingPeer(con::Peer *peer, bool timeout)
3560 {
3561         DSTACK(__FUNCTION_NAME);
3562         dout_server<<"Server::deletingPeer(): peer->id="
3563                         <<peer->id<<", timeout="<<timeout<<std::endl;
3564         
3565         PeerChange c;
3566         c.type = PEER_REMOVED;
3567         c.peer_id = peer->id;
3568         c.timeout = timeout;
3569         m_peer_change_queue.push_back(c);
3570 }
3571
3572 /*
3573         Static send methods
3574 */
3575
3576 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3577 {
3578         DSTACK(__FUNCTION_NAME);
3579         std::ostringstream os(std::ios_base::binary);
3580
3581         writeU16(os, TOCLIENT_HP);
3582         writeU8(os, hp);
3583
3584         // Make data buffer
3585         std::string s = os.str();
3586         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3587         // Send as reliable
3588         con.Send(peer_id, 0, data, true);
3589 }
3590
3591 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3592                 const std::wstring &reason)
3593 {
3594         DSTACK(__FUNCTION_NAME);
3595         std::ostringstream os(std::ios_base::binary);
3596
3597         writeU16(os, TOCLIENT_ACCESS_DENIED);
3598         os<<serializeWideString(reason);
3599
3600         // Make data buffer
3601         std::string s = os.str();
3602         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3603         // Send as reliable
3604         con.Send(peer_id, 0, data, true);
3605 }
3606
3607 /*
3608         Non-static send methods
3609 */
3610
3611 void Server::SendObjectData(float dtime)
3612 {
3613         DSTACK(__FUNCTION_NAME);
3614
3615         core::map<v3s16, bool> stepped_blocks;
3616         
3617         for(core::map<u16, RemoteClient*>::Iterator
3618                 i = m_clients.getIterator();
3619                 i.atEnd() == false; i++)
3620         {
3621                 u16 peer_id = i.getNode()->getKey();
3622                 RemoteClient *client = i.getNode()->getValue();
3623                 assert(client->peer_id == peer_id);
3624                 
3625                 if(client->serialization_version == SER_FMT_VER_INVALID)
3626                         continue;
3627                 
3628                 client->SendObjectData(this, dtime, stepped_blocks);
3629         }
3630 }
3631
3632 void Server::SendPlayerInfos()
3633 {
3634         DSTACK(__FUNCTION_NAME);
3635
3636         //JMutexAutoLock envlock(m_env_mutex);
3637         
3638         // Get connected players
3639         core::list<Player*> players = m_env.getPlayers(true);
3640         
3641         u32 player_count = players.getSize();
3642         u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3643
3644         SharedBuffer<u8> data(datasize);
3645         writeU16(&data[0], TOCLIENT_PLAYERINFO);
3646         
3647         u32 start = 2;
3648         core::list<Player*>::Iterator i;
3649         for(i = players.begin();
3650                         i != players.end(); i++)
3651         {
3652                 Player *player = *i;
3653
3654                 /*dstream<<"Server sending player info for player with "
3655                                 "peer_id="<<player->peer_id<<std::endl;*/
3656                 
3657                 writeU16(&data[start], player->peer_id);
3658                 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3659                 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3660                 start += 2+PLAYERNAME_SIZE;
3661         }
3662
3663         //JMutexAutoLock conlock(m_con_mutex);
3664
3665         // Send as reliable
3666         m_con.SendToAll(0, data, true);
3667 }
3668
3669 void Server::SendInventory(u16 peer_id)
3670 {
3671         DSTACK(__FUNCTION_NAME);
3672         
3673         Player* player = m_env.getPlayer(peer_id);
3674         assert(player);
3675
3676         /*
3677                 Serialize it
3678         */
3679
3680         std::ostringstream os;
3681         //os.imbue(std::locale("C"));
3682
3683         player->inventory.serialize(os);
3684
3685         std::string s = os.str();
3686         
3687         SharedBuffer<u8> data(s.size()+2);
3688         writeU16(&data[0], TOCLIENT_INVENTORY);
3689         memcpy(&data[2], s.c_str(), s.size());
3690         
3691         // Send as reliable
3692         m_con.Send(peer_id, 0, data, true);
3693 }
3694
3695 std::string getWieldedItemString(const Player *player)
3696 {
3697         const InventoryItem *item = player->getWieldItem();
3698         if (item == NULL)
3699                 return std::string("");
3700         std::ostringstream os(std::ios_base::binary);
3701         item->serialize(os);
3702         return os.str();
3703 }
3704
3705 void Server::SendWieldedItem(const Player* player)
3706 {
3707         DSTACK(__FUNCTION_NAME);
3708
3709         assert(player);
3710
3711         std::ostringstream os(std::ios_base::binary);
3712
3713         writeU16(os, TOCLIENT_PLAYERITEM);
3714         writeU16(os, 1);
3715         writeU16(os, player->peer_id);
3716         os<<serializeString(getWieldedItemString(player));
3717
3718         // Make data buffer
3719         std::string s = os.str();
3720         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3721
3722         m_con.SendToAll(0, data, true);
3723 }
3724
3725 void Server::SendPlayerItems()
3726 {
3727         DSTACK(__FUNCTION_NAME);
3728
3729         std::ostringstream os(std::ios_base::binary);
3730         core::list<Player *> players = m_env.getPlayers(true);
3731
3732         writeU16(os, TOCLIENT_PLAYERITEM);
3733         writeU16(os, players.size());
3734         core::list<Player *>::Iterator i;
3735         for(i = players.begin(); i != players.end(); ++i)
3736         {
3737                 Player *p = *i;
3738                 writeU16(os, p->peer_id);
3739                 os<<serializeString(getWieldedItemString(p));
3740         }
3741
3742         // Make data buffer
3743         std::string s = os.str();
3744         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3745
3746         m_con.SendToAll(0, data, true);
3747 }
3748
3749 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3750 {
3751         DSTACK(__FUNCTION_NAME);
3752         
3753         std::ostringstream os(std::ios_base::binary);
3754         u8 buf[12];
3755         
3756         // Write command
3757         writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3758         os.write((char*)buf, 2);
3759         
3760         // Write length
3761         writeU16(buf, message.size());
3762         os.write((char*)buf, 2);
3763         
3764         // Write string
3765         for(u32 i=0; i<message.size(); i++)
3766         {
3767                 u16 w = message[i];
3768                 writeU16(buf, w);
3769                 os.write((char*)buf, 2);
3770         }
3771         
3772         // Make data buffer
3773         std::string s = os.str();
3774         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3775         // Send as reliable
3776         m_con.Send(peer_id, 0, data, true);
3777 }
3778
3779 void Server::BroadcastChatMessage(const std::wstring &message)
3780 {
3781         for(core::map<u16, RemoteClient*>::Iterator
3782                 i = m_clients.getIterator();
3783                 i.atEnd() == false; i++)
3784         {
3785                 // Get client and check that it is valid
3786                 RemoteClient *client = i.getNode()->getValue();
3787                 assert(client->peer_id == i.getNode()->getKey());
3788                 if(client->serialization_version == SER_FMT_VER_INVALID)
3789                         continue;
3790
3791                 SendChatMessage(client->peer_id, message);
3792         }
3793 }
3794
3795 void Server::SendPlayerHP(Player *player)
3796 {
3797         SendHP(m_con, player->peer_id, player->hp);
3798 }
3799
3800 void Server::SendMovePlayer(Player *player)
3801 {
3802         DSTACK(__FUNCTION_NAME);
3803         std::ostringstream os(std::ios_base::binary);
3804
3805         writeU16(os, TOCLIENT_MOVE_PLAYER);
3806         writeV3F1000(os, player->getPosition());
3807         writeF1000(os, player->getPitch());
3808         writeF1000(os, player->getYaw());
3809         
3810         {
3811                 v3f pos = player->getPosition();
3812                 f32 pitch = player->getPitch();
3813                 f32 yaw = player->getYaw();
3814                 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3815                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3816                                 <<" pitch="<<pitch
3817                                 <<" yaw="<<yaw
3818                                 <<std::endl;
3819         }
3820
3821         // Make data buffer
3822         std::string s = os.str();
3823         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3824         // Send as reliable
3825         m_con.Send(player->peer_id, 0, data, true);
3826 }
3827
3828 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3829         core::list<u16> *far_players, float far_d_nodes)
3830 {
3831         float maxd = far_d_nodes*BS;
3832         v3f p_f = intToFloat(p, BS);
3833
3834         // Create packet
3835         u32 replysize = 8;
3836         SharedBuffer<u8> reply(replysize);
3837         writeU16(&reply[0], TOCLIENT_REMOVENODE);
3838         writeS16(&reply[2], p.X);
3839         writeS16(&reply[4], p.Y);
3840         writeS16(&reply[6], p.Z);
3841
3842         for(core::map<u16, RemoteClient*>::Iterator
3843                 i = m_clients.getIterator();
3844                 i.atEnd() == false; i++)
3845         {
3846                 // Get client and check that it is valid
3847                 RemoteClient *client = i.getNode()->getValue();
3848                 assert(client->peer_id == i.getNode()->getKey());
3849                 if(client->serialization_version == SER_FMT_VER_INVALID)
3850                         continue;
3851
3852                 // Don't send if it's the same one
3853                 if(client->peer_id == ignore_id)
3854                         continue;
3855                 
3856                 if(far_players)
3857                 {
3858                         // Get player
3859                         Player *player = m_env.getPlayer(client->peer_id);
3860                         if(player)
3861                         {
3862                                 // If player is far away, only set modified blocks not sent
3863                                 v3f player_pos = player->getPosition();
3864                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3865                                 {
3866                                         far_players->push_back(client->peer_id);
3867                                         continue;
3868                                 }
3869                         }
3870                 }
3871
3872                 // Send as reliable
3873                 m_con.Send(client->peer_id, 0, reply, true);
3874         }
3875 }
3876
3877 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3878                 core::list<u16> *far_players, float far_d_nodes)
3879 {
3880         float maxd = far_d_nodes*BS;
3881         v3f p_f = intToFloat(p, BS);
3882
3883         for(core::map<u16, RemoteClient*>::Iterator
3884                 i = m_clients.getIterator();
3885                 i.atEnd() == false; i++)
3886         {
3887                 // Get client and check that it is valid
3888                 RemoteClient *client = i.getNode()->getValue();
3889                 assert(client->peer_id == i.getNode()->getKey());
3890                 if(client->serialization_version == SER_FMT_VER_INVALID)
3891                         continue;
3892
3893                 // Don't send if it's the same one
3894                 if(client->peer_id == ignore_id)
3895                         continue;
3896
3897                 if(far_players)
3898                 {
3899                         // Get player
3900                         Player *player = m_env.getPlayer(client->peer_id);
3901                         if(player)
3902                         {
3903                                 // If player is far away, only set modified blocks not sent
3904                                 v3f player_pos = player->getPosition();
3905                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3906                                 {
3907                                         far_players->push_back(client->peer_id);
3908                                         continue;
3909                                 }
3910                         }
3911                 }
3912
3913                 // Create packet
3914                 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3915                 SharedBuffer<u8> reply(replysize);
3916                 writeU16(&reply[0], TOCLIENT_ADDNODE);
3917                 writeS16(&reply[2], p.X);
3918                 writeS16(&reply[4], p.Y);
3919                 writeS16(&reply[6], p.Z);
3920                 n.serialize(&reply[8], client->serialization_version);
3921
3922                 // Send as reliable
3923                 m_con.Send(client->peer_id, 0, reply, true);
3924         }
3925 }
3926
3927 void Server::setBlockNotSent(v3s16 p)
3928 {
3929         for(core::map<u16, RemoteClient*>::Iterator
3930                 i = m_clients.getIterator();
3931                 i.atEnd()==false; i++)
3932         {
3933                 RemoteClient *client = i.getNode()->getValue();
3934                 client->SetBlockNotSent(p);
3935         }
3936 }
3937
3938 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3939 {
3940         DSTACK(__FUNCTION_NAME);
3941
3942         v3s16 p = block->getPos();
3943         
3944 #if 0
3945         // Analyze it a bit
3946         bool completely_air = true;
3947         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3948         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3949         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3950         {
3951                 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3952                 {
3953                         completely_air = false;
3954                         x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3955                 }
3956         }
3957
3958         // Print result
3959         dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3960         if(completely_air)
3961                 dstream<<"[completely air] ";
3962         dstream<<std::endl;
3963 #endif
3964
3965         /*
3966                 Create a packet with the block in the right format
3967         */
3968         
3969         std::ostringstream os(std::ios_base::binary);
3970         block->serialize(os, ver);
3971         std::string s = os.str();
3972         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3973
3974         u32 replysize = 8 + blockdata.getSize();
3975         SharedBuffer<u8> reply(replysize);
3976         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3977         writeS16(&reply[2], p.X);
3978         writeS16(&reply[4], p.Y);
3979         writeS16(&reply[6], p.Z);
3980         memcpy(&reply[8], *blockdata, blockdata.getSize());
3981
3982         /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3983                         <<":  \tpacket size: "<<replysize<<std::endl;*/
3984         
3985         /*
3986                 Send packet
3987         */
3988         m_con.Send(peer_id, 1, reply, true);
3989 }
3990
3991 void Server::SendBlocks(float dtime)
3992 {
3993         DSTACK(__FUNCTION_NAME);
3994
3995         JMutexAutoLock envlock(m_env_mutex);
3996         JMutexAutoLock conlock(m_con_mutex);
3997
3998         //TimeTaker timer("Server::SendBlocks");
3999
4000         core::array<PrioritySortedBlockTransfer> queue;
4001
4002         s32 total_sending = 0;
4003         
4004         {
4005                 ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
4006
4007                 for(core::map<u16, RemoteClient*>::Iterator
4008                         i = m_clients.getIterator();
4009                         i.atEnd() == false; i++)
4010                 {
4011                         RemoteClient *client = i.getNode()->getValue();
4012                         assert(client->peer_id == i.getNode()->getKey());
4013
4014                         total_sending += client->SendingCount();
4015                         
4016                         if(client->serialization_version == SER_FMT_VER_INVALID)
4017                                 continue;
4018                         
4019                         client->GetNextBlocks(this, dtime, queue);
4020                 }
4021         }
4022
4023         // Sort.
4024         // Lowest priority number comes first.
4025         // Lowest is most important.
4026         queue.sort();
4027
4028         for(u32 i=0; i<queue.size(); i++)
4029         {
4030                 //TODO: Calculate limit dynamically
4031                 if(total_sending >= g_settings.getS32
4032                                 ("max_simultaneous_block_sends_server_total"))
4033                         break;
4034                 
4035                 PrioritySortedBlockTransfer q = queue[i];
4036
4037                 MapBlock *block = NULL;
4038                 try
4039                 {
4040                         block = m_env.getMap().getBlockNoCreate(q.pos);
4041                 }
4042                 catch(InvalidPositionException &e)
4043                 {
4044                         continue;
4045                 }
4046
4047                 RemoteClient *client = getClient(q.peer_id);
4048
4049                 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4050
4051                 client->SentBlock(q.pos);
4052
4053                 total_sending++;
4054         }
4055 }
4056
4057 /*
4058         Something random
4059 */
4060
4061 void Server::UpdateCrafting(u16 peer_id)
4062 {
4063         DSTACK(__FUNCTION_NAME);
4064         
4065         Player* player = m_env.getPlayer(peer_id);
4066         assert(player);
4067
4068         /*
4069                 Calculate crafting stuff
4070         */
4071         if(g_settings.getBool("creative_mode") == false)
4072         {
4073                 InventoryList *clist = player->inventory.getList("craft");
4074                 InventoryList *rlist = player->inventory.getList("craftresult");
4075
4076                 if(rlist->getUsedSlots() == 0)
4077                         player->craftresult_is_preview = true;
4078
4079                 if(rlist && player->craftresult_is_preview)
4080                 {
4081                         rlist->clearItems();
4082                 }
4083                 if(clist && rlist && player->craftresult_is_preview)
4084                 {
4085                         InventoryItem *items[9];
4086                         for(u16 i=0; i<9; i++)
4087                         {
4088                                 items[i] = clist->getItem(i);
4089                         }
4090                         
4091                         // Get result of crafting grid
4092                         InventoryItem *result = craft_get_result(items);
4093                         if(result)
4094                                 rlist->addItem(result);
4095                 }
4096         
4097         } // if creative_mode == false
4098 }
4099
4100 RemoteClient* Server::getClient(u16 peer_id)
4101 {
4102         DSTACK(__FUNCTION_NAME);
4103         //JMutexAutoLock lock(m_con_mutex);
4104         core::map<u16, RemoteClient*>::Node *n;
4105         n = m_clients.find(peer_id);
4106         // A client should exist for all peers
4107         assert(n != NULL);
4108         return n->getValue();
4109 }
4110
4111 std::wstring Server::getStatusString()
4112 {
4113         std::wostringstream os(std::ios_base::binary);
4114         os<<L"# Server: ";
4115         // Version
4116         os<<L"version="<<narrow_to_wide(VERSION_STRING);
4117         // Uptime
4118         os<<L", uptime="<<m_uptime.get();
4119         // Information about clients
4120         os<<L", clients={";
4121         for(core::map<u16, RemoteClient*>::Iterator
4122                 i = m_clients.getIterator();
4123                 i.atEnd() == false; i++)
4124         {
4125                 // Get client and check that it is valid
4126                 RemoteClient *client = i.getNode()->getValue();
4127                 assert(client->peer_id == i.getNode()->getKey());
4128                 if(client->serialization_version == SER_FMT_VER_INVALID)
4129                         continue;
4130                 // Get player
4131                 Player *player = m_env.getPlayer(client->peer_id);
4132                 // Get name of player
4133                 std::wstring name = L"unknown";
4134                 if(player != NULL)
4135                         name = narrow_to_wide(player->getName());
4136                 // Add name to information string
4137                 os<<name<<L",";
4138         }
4139         os<<L"}";
4140         if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
4141                 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4142         if(g_settings.get("motd") != "")
4143                 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings.get("motd"));
4144         return os.str();
4145 }
4146
4147 v3f findSpawnPos(ServerMap &map)
4148 {
4149         //return v3f(50,50,50)*BS;
4150
4151         v2s16 nodepos;
4152         s16 groundheight = 0;
4153         
4154 #if 0
4155         nodepos = v2s16(0,0);
4156         groundheight = 20;
4157 #endif
4158
4159 #if 1
4160         // Try to find a good place a few times
4161         for(s32 i=0; i<1000; i++)
4162         {
4163                 s32 range = 1 + i;
4164                 // We're going to try to throw the player to this position
4165                 nodepos = v2s16(-range + (myrand()%(range*2)),
4166                                 -range + (myrand()%(range*2)));
4167                 v2s16 sectorpos = getNodeSectorPos(nodepos);
4168                 // Get sector (NOTE: Don't get because it's slow)
4169                 //m_env.getMap().emergeSector(sectorpos);
4170                 // Get ground height at point (fallbacks to heightmap function)
4171                 groundheight = map.findGroundLevel(nodepos);
4172                 // Don't go underwater
4173                 if(groundheight < WATER_LEVEL)
4174                 {
4175                         //dstream<<"-> Underwater"<<std::endl;
4176                         continue;
4177                 }
4178                 // Don't go to high places
4179                 if(groundheight > WATER_LEVEL + 4)
4180                 {
4181                         //dstream<<"-> Underwater"<<std::endl;
4182                         continue;
4183                 }
4184
4185                 // Found a good place
4186                 //dstream<<"Searched through "<<i<<" places."<<std::endl;
4187                 break;
4188         }
4189 #endif
4190         
4191         // If no suitable place was not found, go above water at least.
4192         if(groundheight < WATER_LEVEL)
4193                 groundheight = WATER_LEVEL;
4194
4195         return intToFloat(v3s16(
4196                         nodepos.X,
4197                         groundheight + 3,
4198                         nodepos.Y
4199                         ), BS);
4200 }
4201
4202 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4203 {
4204         /*
4205                 Try to get an existing player
4206         */
4207         Player *player = m_env.getPlayer(name);
4208         if(player != NULL)
4209         {
4210                 // If player is already connected, cancel
4211                 if(player->peer_id != 0)
4212                 {
4213                         dstream<<"emergePlayer(): Player already connected"<<std::endl;
4214                         return NULL;
4215                 }
4216
4217                 // Got one.
4218                 player->peer_id = peer_id;
4219                 
4220                 // Reset inventory to creative if in creative mode
4221                 if(g_settings.getBool("creative_mode"))
4222                 {
4223                         // Warning: double code below
4224                         // Backup actual inventory
4225                         player->inventory_backup = new Inventory();
4226                         *(player->inventory_backup) = player->inventory;
4227                         // Set creative inventory
4228                         craft_set_creative_inventory(player);
4229                 }
4230
4231                 return player;
4232         }
4233
4234         /*
4235                 If player with the wanted peer_id already exists, cancel.
4236         */
4237         if(m_env.getPlayer(peer_id) != NULL)
4238         {
4239                 dstream<<"emergePlayer(): Player with wrong name but same"
4240                                 " peer_id already exists"<<std::endl;
4241                 return NULL;
4242         }
4243         
4244         /*
4245                 Create a new player
4246         */
4247         {
4248                 player = new ServerRemotePlayer();
4249                 //player->peer_id = c.peer_id;
4250                 //player->peer_id = PEER_ID_INEXISTENT;
4251                 player->peer_id = peer_id;
4252                 player->updateName(name);
4253                 m_authmanager.add(name);
4254                 m_authmanager.setPassword(name, password);
4255                 m_authmanager.setPrivs(name,
4256                                 stringToPrivs(g_settings.get("default_privs")));
4257
4258                 /*
4259                         Set player position
4260                 */
4261                 
4262                 dstream<<"Server: Finding spawn place for player \""
4263                                 <<player->getName()<<"\""<<std::endl;
4264
4265                 v3f pos = findSpawnPos(m_env.getServerMap());
4266
4267                 player->setPosition(pos);
4268
4269                 /*
4270                         Add player to environment
4271                 */
4272
4273                 m_env.addPlayer(player);
4274
4275                 /*
4276                         Add stuff to inventory
4277                 */
4278                 
4279                 if(g_settings.getBool("creative_mode"))
4280                 {
4281                         // Warning: double code above
4282                         // Backup actual inventory
4283                         player->inventory_backup = new Inventory();
4284                         *(player->inventory_backup) = player->inventory;
4285                         // Set creative inventory
4286                         craft_set_creative_inventory(player);
4287                 }
4288                 else if(g_settings.getBool("give_initial_stuff"))
4289                 {
4290                         craft_give_initial_stuff(player);
4291                 }
4292
4293                 return player;
4294                 
4295         } // create new player
4296 }
4297
4298 void Server::handlePeerChange(PeerChange &c)
4299 {
4300         JMutexAutoLock envlock(m_env_mutex);
4301         JMutexAutoLock conlock(m_con_mutex);
4302         
4303         if(c.type == PEER_ADDED)
4304         {
4305                 /*
4306                         Add
4307                 */
4308
4309                 // Error check
4310                 core::map<u16, RemoteClient*>::Node *n;
4311                 n = m_clients.find(c.peer_id);
4312                 // The client shouldn't already exist
4313                 assert(n == NULL);
4314
4315                 // Create client
4316                 RemoteClient *client = new RemoteClient();
4317                 client->peer_id = c.peer_id;
4318                 m_clients.insert(client->peer_id, client);
4319
4320         } // PEER_ADDED
4321         else if(c.type == PEER_REMOVED)
4322         {
4323                 /*
4324                         Delete
4325                 */
4326
4327                 // Error check
4328                 core::map<u16, RemoteClient*>::Node *n;
4329                 n = m_clients.find(c.peer_id);
4330                 // The client should exist
4331                 assert(n != NULL);
4332                 
4333                 /*
4334                         Mark objects to be not known by the client
4335                 */
4336                 RemoteClient *client = n->getValue();
4337                 // Handle objects
4338                 for(core::map<u16, bool>::Iterator
4339                                 i = client->m_known_objects.getIterator();
4340                                 i.atEnd()==false; i++)
4341                 {
4342                         // Get object
4343                         u16 id = i.getNode()->getKey();
4344                         ServerActiveObject* obj = m_env.getActiveObject(id);
4345                         
4346                         if(obj && obj->m_known_by_count > 0)
4347                                 obj->m_known_by_count--;
4348                 }
4349
4350                 // Collect information about leaving in chat
4351                 std::wstring message;
4352                 {
4353                         std::wstring name = L"unknown";
4354                         Player *player = m_env.getPlayer(c.peer_id);
4355                         if(player != NULL)
4356                                 name = narrow_to_wide(player->getName());
4357                         
4358                         message += L"*** ";
4359                         message += name;
4360                         message += L" left game";
4361                         if(c.timeout)
4362                                 message += L" (timed out)";
4363                 }
4364
4365                 /*// Delete player
4366                 {
4367                         m_env.removePlayer(c.peer_id);
4368                 }*/
4369
4370                 // Set player client disconnected
4371                 {
4372                         Player *player = m_env.getPlayer(c.peer_id);
4373                         if(player != NULL)
4374                                 player->peer_id = 0;
4375                 }
4376                 
4377                 // Delete client
4378                 delete m_clients[c.peer_id];
4379                 m_clients.remove(c.peer_id);
4380
4381                 // Send player info to all remaining clients
4382                 SendPlayerInfos();
4383                 
4384                 // Send leave chat message to all remaining clients
4385                 BroadcastChatMessage(message);
4386                 
4387         } // PEER_REMOVED
4388         else
4389         {
4390                 assert(0);
4391         }
4392 }
4393
4394 void Server::handlePeerChanges()
4395 {
4396         while(m_peer_change_queue.size() > 0)
4397         {
4398                 PeerChange c = m_peer_change_queue.pop_front();
4399
4400                 dout_server<<"Server: Handling peer change: "
4401                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4402                                 <<std::endl;
4403
4404                 handlePeerChange(c);
4405         }
4406 }
4407
4408 u64 Server::getPlayerPrivs(Player *player)
4409 {
4410         if(player==NULL)
4411                 return 0;
4412         std::string playername = player->getName();
4413         // Local player gets all privileges regardless of
4414         // what's set on their account.
4415         if(g_settings.get("name") == playername)
4416         {
4417                 return PRIV_ALL;
4418         }
4419         else
4420         {
4421                 return getPlayerAuthPrivs(playername);
4422         }
4423 }
4424
4425 void dedicated_server_loop(Server &server, bool &kill)
4426 {
4427         DSTACK(__FUNCTION_NAME);
4428         
4429         dstream<<DTIME<<std::endl;
4430         dstream<<"========================"<<std::endl;
4431         dstream<<"Running dedicated server"<<std::endl;
4432         dstream<<"========================"<<std::endl;
4433         dstream<<std::endl;
4434
4435         IntervalLimiter m_profiler_interval;
4436
4437         for(;;)
4438         {
4439                 // This is kind of a hack but can be done like this
4440                 // because server.step() is very light
4441                 {
4442                         ScopeProfiler sp(&g_profiler, "dedicated server sleep");
4443                         sleep_ms(30);
4444                 }
4445                 server.step(0.030);
4446
4447                 if(server.getShutdownRequested() || kill)
4448                 {
4449                         dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4450                         break;
4451                 }
4452
4453                 /*
4454                         Profiler
4455                 */
4456                 float profiler_print_interval =
4457                                 g_settings.getFloat("profiler_print_interval");
4458                 if(profiler_print_interval != 0)
4459                 {
4460                         if(m_profiler_interval.step(0.030, profiler_print_interval))
4461                         {
4462                                 dstream<<"Profiler:"<<std::endl;
4463                                 g_profiler.print(dstream);
4464                                 g_profiler.clear();
4465                         }
4466                 }
4467                 
4468                 /*
4469                         Player info
4470                 */
4471                 static int counter = 0;
4472                 counter--;
4473                 if(counter <= 0)
4474                 {
4475                         counter = 10;
4476
4477                         core::list<PlayerInfo> list = server.getPlayerInfo();
4478                         core::list<PlayerInfo>::Iterator i;
4479                         static u32 sum_old = 0;
4480                         u32 sum = PIChecksum(list);
4481                         if(sum != sum_old)
4482                         {
4483                                 dstream<<DTIME<<"Player info:"<<std::endl;
4484                                 for(i=list.begin(); i!=list.end(); i++)
4485                                 {
4486                                         i->PrintLine(&dstream);
4487                                 }
4488                         }
4489                         sum_old = sum;
4490                 }
4491         }
4492 }
4493
4494