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