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