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