]> git.lizzy.rs Git - minetest.git/blob - src/server.cpp
Header file tweaking; mainly for speed
[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                 Save players
1145         */
1146         dstream<<"Server: Saving players"<<std::endl;
1147         m_env.serializePlayers(m_mapsavedir);
1148
1149         /*
1150                 Save environment metadata
1151         */
1152         dstream<<"Server: Saving environment metadata"<<std::endl;
1153         m_env.saveMeta(m_mapsavedir);
1154         
1155         /*
1156                 Stop threads
1157         */
1158         stop();
1159         
1160         /*
1161                 Delete clients
1162         */
1163         {
1164                 JMutexAutoLock clientslock(m_con_mutex);
1165
1166                 for(core::map<u16, RemoteClient*>::Iterator
1167                         i = m_clients.getIterator();
1168                         i.atEnd() == false; i++)
1169                 {
1170                         /*// Delete player
1171                         // NOTE: These are removed by env destructor
1172                         {
1173                                 u16 peer_id = i.getNode()->getKey();
1174                                 JMutexAutoLock envlock(m_env_mutex);
1175                                 m_env.removePlayer(peer_id);
1176                         }*/
1177                         
1178                         // Delete client
1179                         delete i.getNode()->getValue();
1180                 }
1181         }
1182 }
1183
1184 void Server::start(unsigned short port)
1185 {
1186         DSTACK(__FUNCTION_NAME);
1187         // Stop thread if already running
1188         m_thread.stop();
1189         
1190         // Initialize connection
1191         m_con.setTimeoutMs(30);
1192         m_con.Serve(port);
1193
1194         // Start thread
1195         m_thread.setRun(true);
1196         m_thread.Start();
1197         
1198         dout_server<<"Server: Started on port "<<port<<std::endl;
1199 }
1200
1201 void Server::stop()
1202 {
1203         DSTACK(__FUNCTION_NAME);
1204
1205         // Stop threads (set run=false first so both start stopping)
1206         m_thread.setRun(false);
1207         m_emergethread.setRun(false);
1208         m_thread.stop();
1209         m_emergethread.stop();
1210         
1211         dout_server<<"Server: Threads stopped"<<std::endl;
1212 }
1213
1214 void Server::step(float dtime)
1215 {
1216         DSTACK(__FUNCTION_NAME);
1217         // Limit a bit
1218         if(dtime > 2.0)
1219                 dtime = 2.0;
1220         {
1221                 JMutexAutoLock lock(m_step_dtime_mutex);
1222                 m_step_dtime += dtime;
1223         }
1224 }
1225
1226 void Server::AsyncRunStep()
1227 {
1228         DSTACK(__FUNCTION_NAME);
1229         
1230         float dtime;
1231         {
1232                 JMutexAutoLock lock1(m_step_dtime_mutex);
1233                 dtime = m_step_dtime;
1234         }
1235         
1236         {
1237                 ScopeProfiler sp(g_profiler, "Server: selecting and sending "
1238                                 "blocks to clients");
1239                 // Send blocks to clients
1240                 SendBlocks(dtime);
1241         }
1242         
1243         if(dtime < 0.001)
1244                 return;
1245
1246         //dstream<<"Server steps "<<dtime<<std::endl;
1247         //dstream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1248         
1249         {
1250                 JMutexAutoLock lock1(m_step_dtime_mutex);
1251                 m_step_dtime -= dtime;
1252         }
1253
1254         /*
1255                 Update uptime
1256         */
1257         {
1258                 m_uptime.set(m_uptime.get() + dtime);
1259         }
1260         
1261         {
1262                 // Process connection's timeouts
1263                 JMutexAutoLock lock2(m_con_mutex);
1264                 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1265                 m_con.RunTimeouts(dtime);
1266         }
1267         
1268         {
1269                 // This has to be called so that the client list gets synced
1270                 // with the peer list of the connection
1271                 ScopeProfiler sp(g_profiler, "Server: peer change handling");
1272                 handlePeerChanges();
1273         }
1274
1275         /*
1276                 Update m_time_of_day and overall game time
1277         */
1278         {
1279                 JMutexAutoLock envlock(m_env_mutex);
1280
1281                 m_time_counter += dtime;
1282                 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1283                 u32 units = (u32)(m_time_counter*speed);
1284                 m_time_counter -= (f32)units / speed;
1285                 
1286                 m_env.setTimeOfDay((m_env.getTimeOfDay() + units) % 24000);
1287                 
1288                 //dstream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1289
1290                 /*
1291                         Send to clients at constant intervals
1292                 */
1293
1294                 m_time_of_day_send_timer -= dtime;
1295                 if(m_time_of_day_send_timer < 0.0)
1296                 {
1297                         m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1298
1299                         //JMutexAutoLock envlock(m_env_mutex);
1300                         JMutexAutoLock conlock(m_con_mutex);
1301
1302                         for(core::map<u16, RemoteClient*>::Iterator
1303                                 i = m_clients.getIterator();
1304                                 i.atEnd() == false; i++)
1305                         {
1306                                 RemoteClient *client = i.getNode()->getValue();
1307                                 //Player *player = m_env.getPlayer(client->peer_id);
1308                                 
1309                                 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1310                                                 m_env.getTimeOfDay());
1311                                 // Send as reliable
1312                                 m_con.Send(client->peer_id, 0, data, true);
1313                         }
1314                 }
1315         }
1316
1317         {
1318                 JMutexAutoLock lock(m_env_mutex);
1319                 // Step environment
1320                 ScopeProfiler sp(g_profiler, "Server: environment step");
1321                 m_env.step(dtime);
1322         }
1323                 
1324         const float map_timer_and_unload_dtime = 5.15;
1325         if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1326         {
1327                 JMutexAutoLock lock(m_env_mutex);
1328                 // Run Map's timers and unload unused data
1329                 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1330                 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
1331                                 g_settings->getFloat("server_unload_unused_data_timeout"));
1332         }
1333         
1334         /*
1335                 Do background stuff
1336         */
1337         
1338         /*
1339                 Transform liquids
1340         */
1341         m_liquid_transform_timer += dtime;
1342         if(m_liquid_transform_timer >= 1.00)
1343         {
1344                 m_liquid_transform_timer -= 1.00;
1345                 
1346                 JMutexAutoLock lock(m_env_mutex);
1347
1348                 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1349
1350                 core::map<v3s16, MapBlock*> modified_blocks;
1351                 m_env.getMap().transformLiquids(modified_blocks);
1352 #if 0           
1353                 /*
1354                         Update lighting
1355                 */
1356                 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1357                 ServerMap &map = ((ServerMap&)m_env.getMap());
1358                 map.updateLighting(modified_blocks, lighting_modified_blocks);
1359                 
1360                 // Add blocks modified by lighting to modified_blocks
1361                 for(core::map<v3s16, MapBlock*>::Iterator
1362                                 i = lighting_modified_blocks.getIterator();
1363                                 i.atEnd() == false; i++)
1364                 {
1365                         MapBlock *block = i.getNode()->getValue();
1366                         modified_blocks.insert(block->getPos(), block);
1367                 }
1368 #endif
1369                 /*
1370                         Set the modified blocks unsent for all the clients
1371                 */
1372                 
1373                 JMutexAutoLock lock2(m_con_mutex);
1374
1375                 for(core::map<u16, RemoteClient*>::Iterator
1376                                 i = m_clients.getIterator();
1377                                 i.atEnd() == false; i++)
1378                 {
1379                         RemoteClient *client = i.getNode()->getValue();
1380                         
1381                         if(modified_blocks.size() > 0)
1382                         {
1383                                 // Remove block from sent history
1384                                 client->SetBlocksNotSent(modified_blocks);
1385                         }
1386                 }
1387         }
1388
1389         // Periodically print some info
1390         {
1391                 float &counter = m_print_info_timer;
1392                 counter += dtime;
1393                 if(counter >= 30.0)
1394                 {
1395                         counter = 0.0;
1396
1397                         JMutexAutoLock lock2(m_con_mutex);
1398
1399                         for(core::map<u16, RemoteClient*>::Iterator
1400                                 i = m_clients.getIterator();
1401                                 i.atEnd() == false; i++)
1402                         {
1403                                 //u16 peer_id = i.getNode()->getKey();
1404                                 RemoteClient *client = i.getNode()->getValue();
1405                                 Player *player = m_env.getPlayer(client->peer_id);
1406                                 if(player==NULL)
1407                                         continue;
1408                                 std::cout<<player->getName()<<"\t";
1409                                 client->PrintInfo(std::cout);
1410                         }
1411                 }
1412         }
1413
1414         //if(g_settings->getBool("enable_experimental"))
1415         {
1416
1417         /*
1418                 Check added and deleted active objects
1419         */
1420         {
1421                 //dstream<<"Server: Checking added and deleted active objects"<<std::endl;
1422                 JMutexAutoLock envlock(m_env_mutex);
1423                 JMutexAutoLock conlock(m_con_mutex);
1424
1425                 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objects");
1426
1427                 // Radius inside which objects are active
1428                 s16 radius = 32;
1429
1430                 for(core::map<u16, RemoteClient*>::Iterator
1431                         i = m_clients.getIterator();
1432                         i.atEnd() == false; i++)
1433                 {
1434                         RemoteClient *client = i.getNode()->getValue();
1435                         Player *player = m_env.getPlayer(client->peer_id);
1436                         if(player==NULL)
1437                         {
1438                                 // This can happen if the client timeouts somehow
1439                                 /*dstream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1440                                                 <<client->peer_id
1441                                                 <<" has no associated player"<<std::endl;*/
1442                                 continue;
1443                         }
1444                         v3s16 pos = floatToInt(player->getPosition(), BS);
1445
1446                         core::map<u16, bool> removed_objects;
1447                         core::map<u16, bool> added_objects;
1448                         m_env.getRemovedActiveObjects(pos, radius,
1449                                         client->m_known_objects, removed_objects);
1450                         m_env.getAddedActiveObjects(pos, radius,
1451                                         client->m_known_objects, added_objects);
1452                         
1453                         // Ignore if nothing happened
1454                         if(removed_objects.size() == 0 && added_objects.size() == 0)
1455                         {
1456                                 //dstream<<"INFO: active objects: none changed"<<std::endl;
1457                                 continue;
1458                         }
1459                         
1460                         std::string data_buffer;
1461
1462                         char buf[4];
1463                         
1464                         // Handle removed objects
1465                         writeU16((u8*)buf, removed_objects.size());
1466                         data_buffer.append(buf, 2);
1467                         for(core::map<u16, bool>::Iterator
1468                                         i = removed_objects.getIterator();
1469                                         i.atEnd()==false; i++)
1470                         {
1471                                 // Get object
1472                                 u16 id = i.getNode()->getKey();
1473                                 ServerActiveObject* obj = m_env.getActiveObject(id);
1474
1475                                 // Add to data buffer for sending
1476                                 writeU16((u8*)buf, i.getNode()->getKey());
1477                                 data_buffer.append(buf, 2);
1478                                 
1479                                 // Remove from known objects
1480                                 client->m_known_objects.remove(i.getNode()->getKey());
1481
1482                                 if(obj && obj->m_known_by_count > 0)
1483                                         obj->m_known_by_count--;
1484                         }
1485
1486                         // Handle added objects
1487                         writeU16((u8*)buf, added_objects.size());
1488                         data_buffer.append(buf, 2);
1489                         for(core::map<u16, bool>::Iterator
1490                                         i = added_objects.getIterator();
1491                                         i.atEnd()==false; i++)
1492                         {
1493                                 // Get object
1494                                 u16 id = i.getNode()->getKey();
1495                                 ServerActiveObject* obj = m_env.getActiveObject(id);
1496                                 
1497                                 // Get object type
1498                                 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1499                                 if(obj == NULL)
1500                                         dstream<<"WARNING: "<<__FUNCTION_NAME
1501                                                         <<": NULL object"<<std::endl;
1502                                 else
1503                                         type = obj->getType();
1504
1505                                 // Add to data buffer for sending
1506                                 writeU16((u8*)buf, id);
1507                                 data_buffer.append(buf, 2);
1508                                 writeU8((u8*)buf, type);
1509                                 data_buffer.append(buf, 1);
1510                                 
1511                                 if(obj)
1512                                         data_buffer.append(serializeLongString(
1513                                                         obj->getClientInitializationData()));
1514                                 else
1515                                         data_buffer.append(serializeLongString(""));
1516
1517                                 // Add to known objects
1518                                 client->m_known_objects.insert(i.getNode()->getKey(), false);
1519
1520                                 if(obj)
1521                                         obj->m_known_by_count++;
1522                         }
1523
1524                         // Send packet
1525                         SharedBuffer<u8> reply(2 + data_buffer.size());
1526                         writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1527                         memcpy((char*)&reply[2], data_buffer.c_str(),
1528                                         data_buffer.size());
1529                         // Send as reliable
1530                         m_con.Send(client->peer_id, 0, reply, true);
1531
1532                         dstream<<"INFO: Server: Sent object remove/add: "
1533                                         <<removed_objects.size()<<" removed, "
1534                                         <<added_objects.size()<<" added, "
1535                                         <<"packet size is "<<reply.getSize()<<std::endl;
1536                 }
1537
1538 #if 0
1539                 /*
1540                         Collect a list of all the objects known by the clients
1541                         and report it back to the environment.
1542                 */
1543
1544                 core::map<u16, bool> all_known_objects;
1545
1546                 for(core::map<u16, RemoteClient*>::Iterator
1547                         i = m_clients.getIterator();
1548                         i.atEnd() == false; i++)
1549                 {
1550                         RemoteClient *client = i.getNode()->getValue();
1551                         // Go through all known objects of client
1552                         for(core::map<u16, bool>::Iterator
1553                                         i = client->m_known_objects.getIterator();
1554                                         i.atEnd()==false; i++)
1555                         {
1556                                 u16 id = i.getNode()->getKey();
1557                                 all_known_objects[id] = true;
1558                         }
1559                 }
1560                 
1561                 m_env.setKnownActiveObjects(whatever);
1562 #endif
1563
1564         }
1565
1566         /*
1567                 Send object messages
1568         */
1569         {
1570                 JMutexAutoLock envlock(m_env_mutex);
1571                 JMutexAutoLock conlock(m_con_mutex);
1572
1573                 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1574
1575                 // Key = object id
1576                 // Value = data sent by object
1577                 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1578
1579                 // Get active object messages from environment
1580                 for(;;)
1581                 {
1582                         ActiveObjectMessage aom = m_env.getActiveObjectMessage();
1583                         if(aom.id == 0)
1584                                 break;
1585                         
1586                         core::list<ActiveObjectMessage>* message_list = NULL;
1587                         core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1588                         n = buffered_messages.find(aom.id);
1589                         if(n == NULL)
1590                         {
1591                                 message_list = new core::list<ActiveObjectMessage>;
1592                                 buffered_messages.insert(aom.id, message_list);
1593                         }
1594                         else
1595                         {
1596                                 message_list = n->getValue();
1597                         }
1598                         message_list->push_back(aom);
1599                 }
1600                 
1601                 // Route data to every client
1602                 for(core::map<u16, RemoteClient*>::Iterator
1603                         i = m_clients.getIterator();
1604                         i.atEnd()==false; i++)
1605                 {
1606                         RemoteClient *client = i.getNode()->getValue();
1607                         std::string reliable_data;
1608                         std::string unreliable_data;
1609                         // Go through all objects in message buffer
1610                         for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1611                                         j = buffered_messages.getIterator();
1612                                         j.atEnd()==false; j++)
1613                         {
1614                                 // If object is not known by client, skip it
1615                                 u16 id = j.getNode()->getKey();
1616                                 if(client->m_known_objects.find(id) == NULL)
1617                                         continue;
1618                                 // Get message list of object
1619                                 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1620                                 // Go through every message
1621                                 for(core::list<ActiveObjectMessage>::Iterator
1622                                                 k = list->begin(); k != list->end(); k++)
1623                                 {
1624                                         // Compose the full new data with header
1625                                         ActiveObjectMessage aom = *k;
1626                                         std::string new_data;
1627                                         // Add object id
1628                                         char buf[2];
1629                                         writeU16((u8*)&buf[0], aom.id);
1630                                         new_data.append(buf, 2);
1631                                         // Add data
1632                                         new_data += serializeString(aom.datastring);
1633                                         // Add data to buffer
1634                                         if(aom.reliable)
1635                                                 reliable_data += new_data;
1636                                         else
1637                                                 unreliable_data += new_data;
1638                                 }
1639                         }
1640                         /*
1641                                 reliable_data and unreliable_data are now ready.
1642                                 Send them.
1643                         */
1644                         if(reliable_data.size() > 0)
1645                         {
1646                                 SharedBuffer<u8> reply(2 + reliable_data.size());
1647                                 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1648                                 memcpy((char*)&reply[2], reliable_data.c_str(),
1649                                                 reliable_data.size());
1650                                 // Send as reliable
1651                                 m_con.Send(client->peer_id, 0, reply, true);
1652                         }
1653                         if(unreliable_data.size() > 0)
1654                         {
1655                                 SharedBuffer<u8> reply(2 + unreliable_data.size());
1656                                 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1657                                 memcpy((char*)&reply[2], unreliable_data.c_str(),
1658                                                 unreliable_data.size());
1659                                 // Send as unreliable
1660                                 m_con.Send(client->peer_id, 0, reply, false);
1661                         }
1662
1663                         /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1664                         {
1665                                 dstream<<"INFO: Server: Size of object message data: "
1666                                                 <<"reliable: "<<reliable_data.size()
1667                                                 <<", unreliable: "<<unreliable_data.size()
1668                                                 <<std::endl;
1669                         }*/
1670                 }
1671
1672                 // Clear buffered_messages
1673                 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1674                                 i = buffered_messages.getIterator();
1675                                 i.atEnd()==false; i++)
1676                 {
1677                         delete i.getNode()->getValue();
1678                 }
1679         }
1680
1681         } // enable_experimental
1682
1683         /*
1684                 Send queued-for-sending map edit events.
1685         */
1686         {
1687                 // Don't send too many at a time
1688                 //u32 count = 0;
1689
1690                 // Single change sending is disabled if queue size is not small
1691                 bool disable_single_change_sending = false;
1692                 if(m_unsent_map_edit_queue.size() >= 4)
1693                         disable_single_change_sending = true;
1694
1695                 bool got_any_events = false;
1696
1697                 // We'll log the amount of each
1698                 Profiler prof;
1699
1700                 while(m_unsent_map_edit_queue.size() != 0)
1701                 {
1702                         got_any_events = true;
1703
1704                         MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1705                         
1706                         // Players far away from the change are stored here.
1707                         // Instead of sending the changes, MapBlocks are set not sent
1708                         // for them.
1709                         core::list<u16> far_players;
1710
1711                         if(event->type == MEET_ADDNODE)
1712                         {
1713                                 //dstream<<"Server: MEET_ADDNODE"<<std::endl;
1714                                 prof.add("MEET_ADDNODE", 1);
1715                                 if(disable_single_change_sending)
1716                                         sendAddNode(event->p, event->n, event->already_known_by_peer,
1717                                                         &far_players, 5);
1718                                 else
1719                                         sendAddNode(event->p, event->n, event->already_known_by_peer,
1720                                                         &far_players, 30);
1721                         }
1722                         else if(event->type == MEET_REMOVENODE)
1723                         {
1724                                 //dstream<<"Server: MEET_REMOVENODE"<<std::endl;
1725                                 prof.add("MEET_REMOVENODE", 1);
1726                                 if(disable_single_change_sending)
1727                                         sendRemoveNode(event->p, event->already_known_by_peer,
1728                                                         &far_players, 5);
1729                                 else
1730                                         sendRemoveNode(event->p, event->already_known_by_peer,
1731                                                         &far_players, 30);
1732                         }
1733                         else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1734                         {
1735                                 dstream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1736                                 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1737                                 setBlockNotSent(event->p);
1738                         }
1739                         else if(event->type == MEET_OTHER)
1740                         {
1741                                 dstream<<"Server: MEET_OTHER"<<std::endl;
1742                                 prof.add("MEET_OTHER", 1);
1743                                 for(core::map<v3s16, bool>::Iterator
1744                                                 i = event->modified_blocks.getIterator();
1745                                                 i.atEnd()==false; i++)
1746                                 {
1747                                         v3s16 p = i.getNode()->getKey();
1748                                         setBlockNotSent(p);
1749                                 }
1750                         }
1751                         else
1752                         {
1753                                 prof.add("unknown", 1);
1754                                 dstream<<"WARNING: Server: Unknown MapEditEvent "
1755                                                 <<((u32)event->type)<<std::endl;
1756                         }
1757                         
1758                         /*
1759                                 Set blocks not sent to far players
1760                         */
1761                         if(far_players.size() > 0)
1762                         {
1763                                 // Convert list format to that wanted by SetBlocksNotSent
1764                                 core::map<v3s16, MapBlock*> modified_blocks2;
1765                                 for(core::map<v3s16, bool>::Iterator
1766                                                 i = event->modified_blocks.getIterator();
1767                                                 i.atEnd()==false; i++)
1768                                 {
1769                                         v3s16 p = i.getNode()->getKey();
1770                                         modified_blocks2.insert(p,
1771                                                         m_env.getMap().getBlockNoCreateNoEx(p));
1772                                 }
1773                                 // Set blocks not sent
1774                                 for(core::list<u16>::Iterator
1775                                                 i = far_players.begin();
1776                                                 i != far_players.end(); i++)
1777                                 {
1778                                         u16 peer_id = *i;
1779                                         RemoteClient *client = getClient(peer_id);
1780                                         if(client==NULL)
1781                                                 continue;
1782                                         client->SetBlocksNotSent(modified_blocks2);
1783                                 }
1784                         }
1785
1786                         delete event;
1787
1788                         /*// Don't send too many at a time
1789                         count++;
1790                         if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1791                                 break;*/
1792                 }
1793
1794                 if(got_any_events)
1795                 {
1796                         dstream<<"Server: MapEditEvents:"<<std::endl;
1797                         prof.print(dstream);
1798                 }
1799                 
1800         }
1801
1802         /*
1803                 Send object positions
1804                 TODO: Get rid of MapBlockObjects
1805         */
1806         {
1807                 float &counter = m_objectdata_timer;
1808                 counter += dtime;
1809                 if(counter >= g_settings->getFloat("objectdata_interval"))
1810                 {
1811                         JMutexAutoLock lock1(m_env_mutex);
1812                         JMutexAutoLock lock2(m_con_mutex);
1813
1814                         ScopeProfiler sp(g_profiler, "Server: sending mbo positions");
1815
1816                         SendObjectData(counter);
1817
1818                         counter = 0.0;
1819                 }
1820         }
1821         
1822         /*
1823                 Trigger emergethread (it somehow gets to a non-triggered but
1824                 bysy state sometimes)
1825         */
1826         {
1827                 float &counter = m_emergethread_trigger_timer;
1828                 counter += dtime;
1829                 if(counter >= 2.0)
1830                 {
1831                         counter = 0.0;
1832                         
1833                         m_emergethread.trigger();
1834                 }
1835         }
1836
1837         // Save map, players and auth stuff
1838         {
1839                 float &counter = m_savemap_timer;
1840                 counter += dtime;
1841                 if(counter >= g_settings->getFloat("server_map_save_interval"))
1842                 {
1843                         counter = 0.0;
1844
1845                         ScopeProfiler sp(g_profiler, "Server: saving stuff");
1846
1847                         // Auth stuff
1848                         if(m_authmanager.isModified())
1849                                 m_authmanager.save();
1850
1851                         //Bann stuff
1852                         if(m_banmanager.isModified())
1853                                 m_banmanager.save();
1854                         
1855                         // Map
1856                         JMutexAutoLock lock(m_env_mutex);
1857
1858                         /*// Unload unused data (delete from memory)
1859                         m_env.getMap().unloadUnusedData(
1860                                         g_settings->getFloat("server_unload_unused_sectors_timeout"));
1861                                         */
1862                         /*u32 deleted_count = m_env.getMap().unloadUnusedData(
1863                                         g_settings->getFloat("server_unload_unused_sectors_timeout"));
1864                                         */
1865
1866                         // Save only changed parts
1867                         m_env.getMap().save(true);
1868
1869                         /*if(deleted_count > 0)
1870                         {
1871                                 dout_server<<"Server: Unloaded "<<deleted_count
1872                                                 <<" blocks from memory"<<std::endl;
1873                         }*/
1874
1875                         // Save players
1876                         m_env.serializePlayers(m_mapsavedir);
1877                         
1878                         // Save environment metadata
1879                         m_env.saveMeta(m_mapsavedir);
1880                 }
1881         }
1882 }
1883
1884 void Server::Receive()
1885 {
1886         DSTACK(__FUNCTION_NAME);
1887         u32 data_maxsize = 10000;
1888         Buffer<u8> data(data_maxsize);
1889         u16 peer_id;
1890         u32 datasize;
1891         try{
1892                 {
1893                         JMutexAutoLock conlock(m_con_mutex);
1894                         datasize = m_con.Receive(peer_id, *data, data_maxsize);
1895                 }
1896
1897                 // This has to be called so that the client list gets synced
1898                 // with the peer list of the connection
1899                 handlePeerChanges();
1900
1901                 ProcessData(*data, datasize, peer_id);
1902         }
1903         catch(con::InvalidIncomingDataException &e)
1904         {
1905                 derr_server<<"Server::Receive(): "
1906                                 "InvalidIncomingDataException: what()="
1907                                 <<e.what()<<std::endl;
1908         }
1909         catch(con::PeerNotFoundException &e)
1910         {
1911                 //NOTE: This is not needed anymore
1912                 
1913                 // The peer has been disconnected.
1914                 // Find the associated player and remove it.
1915
1916                 /*JMutexAutoLock envlock(m_env_mutex);
1917
1918                 dout_server<<"ServerThread: peer_id="<<peer_id
1919                                 <<" has apparently closed connection. "
1920                                 <<"Removing player."<<std::endl;
1921
1922                 m_env.removePlayer(peer_id);*/
1923         }
1924 }
1925
1926 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1927 {
1928         DSTACK(__FUNCTION_NAME);
1929         // Environment is locked first.
1930         JMutexAutoLock envlock(m_env_mutex);
1931         JMutexAutoLock conlock(m_con_mutex);
1932         
1933         con::Peer *peer;
1934         try{
1935                 peer = m_con.GetPeer(peer_id);
1936         }
1937         catch(con::PeerNotFoundException &e)
1938         {
1939                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1940                                 <<peer_id<<" not found"<<std::endl;
1941                 return;
1942         }
1943
1944         // drop player if is ip is banned
1945         if(m_banmanager.isIpBanned(peer->address.serializeString())){
1946                 SendAccessDenied(m_con, peer_id,
1947                                 L"Your ip is banned. Banned name was "
1948                                 +narrow_to_wide(m_banmanager.getBanName(
1949                                         peer->address.serializeString())));
1950                 m_con.deletePeer(peer_id, false);
1951                 return;
1952         }
1953         
1954         u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1955
1956         try
1957         {
1958
1959         if(datasize < 2)
1960                 return;
1961
1962         ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1963         
1964         if(command == TOSERVER_INIT)
1965         {
1966                 // [0] u16 TOSERVER_INIT
1967                 // [2] u8 SER_FMT_VER_HIGHEST
1968                 // [3] u8[20] player_name
1969                 // [23] u8[28] password <--- can be sent without this, from old versions
1970
1971                 if(datasize < 2+1+PLAYERNAME_SIZE)
1972                         return;
1973
1974                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1975                                 <<peer->id<<std::endl;
1976
1977                 // First byte after command is maximum supported
1978                 // serialization version
1979                 u8 client_max = data[2];
1980                 u8 our_max = SER_FMT_VER_HIGHEST;
1981                 // Use the highest version supported by both
1982                 u8 deployed = core::min_(client_max, our_max);
1983                 // If it's lower than the lowest supported, give up.
1984                 if(deployed < SER_FMT_VER_LOWEST)
1985                         deployed = SER_FMT_VER_INVALID;
1986
1987                 //peer->serialization_version = deployed;
1988                 getClient(peer->id)->pending_serialization_version = deployed;
1989                 
1990                 if(deployed == SER_FMT_VER_INVALID)
1991                 {
1992                         derr_server<<DTIME<<"Server: Cannot negotiate "
1993                                         "serialization version with peer "
1994                                         <<peer_id<<std::endl;
1995                         SendAccessDenied(m_con, peer_id,
1996                                         L"Your client is too old (map format)");
1997                         return;
1998                 }
1999                 
2000                 /*
2001                         Read and check network protocol version
2002                 */
2003
2004                 u16 net_proto_version = 0;
2005                 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2006                 {
2007                         net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2008                 }
2009
2010                 getClient(peer->id)->net_proto_version = net_proto_version;
2011
2012                 if(net_proto_version == 0)
2013                 {
2014                         SendAccessDenied(m_con, peer_id,
2015                                         L"Your client is too old. Please upgrade.");
2016                         return;
2017                 }
2018                 
2019                 /* Uhh... this should actually be a warning but let's do it like this */
2020                 if(net_proto_version < 2)
2021                 {
2022                         SendAccessDenied(m_con, peer_id,
2023                                         L"Your client is too old. Please upgrade.");
2024                         return;
2025                 }
2026
2027                 /*
2028                         Set up player
2029                 */
2030                 
2031                 // Get player name
2032                 char playername[PLAYERNAME_SIZE];
2033                 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2034                 {
2035                         playername[i] = data[3+i];
2036                 }
2037                 playername[PLAYERNAME_SIZE-1] = 0;
2038                 
2039                 if(playername[0]=='\0')
2040                 {
2041                         derr_server<<DTIME<<"Server: Player has empty name"<<std::endl;
2042                         SendAccessDenied(m_con, peer_id,
2043                                         L"Empty name");
2044                         return;
2045                 }
2046
2047                 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2048                 {
2049                         derr_server<<DTIME<<"Server: Player has invalid name"<<std::endl;
2050                         SendAccessDenied(m_con, peer_id,
2051                                         L"Name contains unallowed characters");
2052                         return;
2053                 }
2054
2055                 // Get password
2056                 char password[PASSWORD_SIZE];
2057                 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2058                 {
2059                         // old version - assume blank password
2060                         password[0] = 0;
2061                 }
2062                 else
2063                 {
2064                                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2065                                 {
2066                                         password[i] = data[23+i];
2067                                 }
2068                                 password[PASSWORD_SIZE-1] = 0;
2069                 }
2070                 
2071                 std::string checkpwd;
2072                 if(m_authmanager.exists(playername))
2073                 {
2074                         checkpwd = m_authmanager.getPassword(playername);
2075                 }
2076                 else
2077                 {
2078                         checkpwd = g_settings->get("default_password");
2079                 }
2080                 
2081                 /*dstream<<"Server: Client gave password '"<<password
2082                                 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2083                 
2084                 if(password != checkpwd && m_authmanager.exists(playername))
2085                 {
2086                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
2087                                         <<": supplied invalid password for "
2088                                         <<playername<<std::endl;
2089                         SendAccessDenied(m_con, peer_id, L"Invalid password");
2090                         return;
2091                 }
2092                 
2093                 // Add player to auth manager
2094                 if(m_authmanager.exists(playername) == false)
2095                 {
2096                         derr_server<<DTIME<<"Server: adding player "<<playername
2097                                         <<" to auth manager"<<std::endl;
2098                         m_authmanager.add(playername);
2099                         m_authmanager.setPassword(playername, checkpwd);
2100                         m_authmanager.setPrivs(playername,
2101                                         stringToPrivs(g_settings->get("default_privs")));
2102                         m_authmanager.save();
2103                 }
2104                 
2105                 // Enforce user limit.
2106                 // Don't enforce for users that have some admin right
2107                 if(m_clients.size() >= g_settings->getU16("max_users") &&
2108                                 (m_authmanager.getPrivs(playername)
2109                                         & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS)) == 0 &&
2110                                 playername != g_settings->get("name"))
2111                 {
2112                         SendAccessDenied(m_con, peer_id, L"Too many users.");
2113                         return;
2114                 }
2115
2116                 // Get player
2117                 Player *player = emergePlayer(playername, password, peer_id);
2118
2119                 /*{
2120                         // DEBUG: Test serialization
2121                         std::ostringstream test_os;
2122                         player->serialize(test_os);
2123                         dstream<<"Player serialization test: \""<<test_os.str()
2124                                         <<"\""<<std::endl;
2125                         std::istringstream test_is(test_os.str());
2126                         player->deSerialize(test_is);
2127                 }*/
2128
2129                 // If failed, cancel
2130                 if(player == NULL)
2131                 {
2132                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
2133                                         <<": failed to emerge player"<<std::endl;
2134                         return;
2135                 }
2136
2137                 /*
2138                 // If a client is already connected to the player, cancel
2139                 if(player->peer_id != 0)
2140                 {
2141                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
2142                                         <<" tried to connect to "
2143                                         "an already connected player (peer_id="
2144                                         <<player->peer_id<<")"<<std::endl;
2145                         return;
2146                 }
2147                 // Set client of player
2148                 player->peer_id = peer_id;
2149                 */
2150
2151                 // Check if player doesn't exist
2152                 if(player == NULL)
2153                         throw con::InvalidIncomingDataException
2154                                 ("Server::ProcessData(): INIT: Player doesn't exist");
2155
2156                 /*// update name if it was supplied
2157                 if(datasize >= 20+3)
2158                 {
2159                         data[20+3-1] = 0;
2160                         player->updateName((const char*)&data[3]);
2161                 }*/
2162                 
2163                 /*
2164                         Answer with a TOCLIENT_INIT
2165                 */
2166                 {
2167                         SharedBuffer<u8> reply(2+1+6+8);
2168                         writeU16(&reply[0], TOCLIENT_INIT);
2169                         writeU8(&reply[2], deployed);
2170                         writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2171                         writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
2172                         
2173                         // Send as reliable
2174                         m_con.Send(peer_id, 0, reply, true);
2175                 }
2176
2177                 /*
2178                         Send complete position information
2179                 */
2180                 SendMovePlayer(player);
2181
2182                 return;
2183         }
2184
2185         if(command == TOSERVER_INIT2)
2186         {
2187                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
2188                                 <<peer->id<<std::endl;
2189
2190
2191                 getClient(peer->id)->serialization_version
2192                                 = getClient(peer->id)->pending_serialization_version;
2193
2194                 /*
2195                         Send some initialization data
2196                 */
2197                 
2198                 // Send player info to all players
2199                 SendPlayerInfos();
2200
2201                 // Send inventory to player
2202                 UpdateCrafting(peer->id);
2203                 SendInventory(peer->id);
2204
2205                 // Send player items to all players
2206                 SendPlayerItems();
2207
2208                 // Send HP
2209                 {
2210                         Player *player = m_env.getPlayer(peer_id);
2211                         SendPlayerHP(player);
2212                 }
2213                 
2214                 // Send time of day
2215                 {
2216                         SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2217                                         m_env.getTimeOfDay());
2218                         m_con.Send(peer->id, 0, data, true);
2219                 }
2220                 
2221                 // Send information about server to player in chat
2222                 SendChatMessage(peer_id, getStatusString());
2223                 
2224                 // Send information about joining in chat
2225                 {
2226                         std::wstring name = L"unknown";
2227                         Player *player = m_env.getPlayer(peer_id);
2228                         if(player != NULL)
2229                                 name = narrow_to_wide(player->getName());
2230                         
2231                         std::wstring message;
2232                         message += L"*** ";
2233                         message += name;
2234                         message += L" joined game";
2235                         BroadcastChatMessage(message);
2236                 }
2237                 
2238                 // Warnings about protocol version can be issued here
2239                 /*if(getClient(peer->id)->net_proto_version == 0)
2240                 {
2241                         SendChatMessage(peer_id, L"# Server: NOTE: YOUR CLIENT IS OLD AND DOES NOT WORK PROPERLY WITH THIS SERVER");
2242                 }*/
2243
2244                 return;
2245         }
2246
2247         if(peer_ser_ver == SER_FMT_VER_INVALID)
2248         {
2249                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
2250                                 " serialization format invalid or not initialized."
2251                                 " Skipping incoming command="<<command<<std::endl;
2252                 return;
2253         }
2254         
2255         Player *player = m_env.getPlayer(peer_id);
2256
2257         if(player == NULL){
2258                 derr_server<<"Server::ProcessData(): Cancelling: "
2259                                 "No player for peer_id="<<peer_id
2260                                 <<std::endl;
2261                 return;
2262         }
2263         if(command == TOSERVER_PLAYERPOS)
2264         {
2265                 if(datasize < 2+12+12+4+4)
2266                         return;
2267         
2268                 u32 start = 0;
2269                 v3s32 ps = readV3S32(&data[start+2]);
2270                 v3s32 ss = readV3S32(&data[start+2+12]);
2271                 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2272                 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2273                 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2274                 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2275                 pitch = wrapDegrees(pitch);
2276                 yaw = wrapDegrees(yaw);
2277                 player->setPosition(position);
2278                 player->setSpeed(speed);
2279                 player->setPitch(pitch);
2280                 player->setYaw(yaw);
2281                 
2282                 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2283                                 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2284                                 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2285         }
2286         else if(command == TOSERVER_GOTBLOCKS)
2287         {
2288                 if(datasize < 2+1)
2289                         return;
2290                 
2291                 /*
2292                         [0] u16 command
2293                         [2] u8 count
2294                         [3] v3s16 pos_0
2295                         [3+6] v3s16 pos_1
2296                         ...
2297                 */
2298
2299                 u16 count = data[2];
2300                 for(u16 i=0; i<count; i++)
2301                 {
2302                         if((s16)datasize < 2+1+(i+1)*6)
2303                                 throw con::InvalidIncomingDataException
2304                                         ("GOTBLOCKS length is too short");
2305                         v3s16 p = readV3S16(&data[2+1+i*6]);
2306                         /*dstream<<"Server: GOTBLOCKS ("
2307                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2308                         RemoteClient *client = getClient(peer_id);
2309                         client->GotBlock(p);
2310                 }
2311         }
2312         else if(command == TOSERVER_DELETEDBLOCKS)
2313         {
2314                 if(datasize < 2+1)
2315                         return;
2316                 
2317                 /*
2318                         [0] u16 command
2319                         [2] u8 count
2320                         [3] v3s16 pos_0
2321                         [3+6] v3s16 pos_1
2322                         ...
2323                 */
2324
2325                 u16 count = data[2];
2326                 for(u16 i=0; i<count; i++)
2327                 {
2328                         if((s16)datasize < 2+1+(i+1)*6)
2329                                 throw con::InvalidIncomingDataException
2330                                         ("DELETEDBLOCKS length is too short");
2331                         v3s16 p = readV3S16(&data[2+1+i*6]);
2332                         /*dstream<<"Server: DELETEDBLOCKS ("
2333                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2334                         RemoteClient *client = getClient(peer_id);
2335                         client->SetBlockNotSent(p);
2336                 }
2337         }
2338         else if(command == TOSERVER_CLICK_OBJECT)
2339         {
2340                 if(datasize < 13)
2341                         return;
2342
2343                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2344                         return;
2345
2346                 /*
2347                         [0] u16 command
2348                         [2] u8 button (0=left, 1=right)
2349                         [3] v3s16 block
2350                         [9] s16 id
2351                         [11] u16 item
2352                 */
2353                 u8 button = readU8(&data[2]);
2354                 v3s16 p;
2355                 p.X = readS16(&data[3]);
2356                 p.Y = readS16(&data[5]);
2357                 p.Z = readS16(&data[7]);
2358                 s16 id = readS16(&data[9]);
2359                 //u16 item_i = readU16(&data[11]);
2360
2361                 MapBlock *block = NULL;
2362                 try
2363                 {
2364                         block = m_env.getMap().getBlockNoCreate(p);
2365                 }
2366                 catch(InvalidPositionException &e)
2367                 {
2368                         derr_server<<"CLICK_OBJECT block not found"<<std::endl;
2369                         return;
2370                 }
2371
2372                 MapBlockObject *obj = block->getObject(id);
2373
2374                 if(obj == NULL)
2375                 {
2376                         derr_server<<"CLICK_OBJECT object not found"<<std::endl;
2377                         return;
2378                 }
2379
2380                 //TODO: Check that object is reasonably close
2381                 
2382                 // Left click
2383                 if(button == 0)
2384                 {
2385                         InventoryList *ilist = player->inventory.getList("main");
2386                         if(g_settings->getBool("creative_mode") == false && ilist != NULL)
2387                         {
2388                         
2389                                 // Skip if inventory has no free space
2390                                 if(ilist->getUsedSlots() == ilist->getSize())
2391                                 {
2392                                         dout_server<<"Player inventory has no free space"<<std::endl;
2393                                         return;
2394                                 }
2395                                 
2396                                 /*
2397                                         Create the inventory item
2398                                 */
2399                                 InventoryItem *item = NULL;
2400                                 // If it is an item-object, take the item from it
2401                                 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
2402                                 {
2403                                         item = ((ItemObject*)obj)->createInventoryItem();
2404                                 }
2405                                 // Else create an item of the object
2406                                 else
2407                                 {
2408                                         item = new MapBlockObjectItem
2409                                                         (obj->getInventoryString());
2410                                 }
2411                                 
2412                                 // Add to inventory and send inventory
2413                                 ilist->addItem(item);
2414                                 UpdateCrafting(player->peer_id);
2415                                 SendInventory(player->peer_id);
2416                         }
2417
2418                         // Remove from block
2419                         block->removeObject(id);
2420                 }
2421         }
2422         else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2423         {
2424                 if(datasize < 7)
2425                         return;
2426
2427                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2428                         return;
2429
2430                 /*
2431                         length: 7
2432                         [0] u16 command
2433                         [2] u8 button (0=left, 1=right)
2434                         [3] u16 id
2435                         [5] u16 item
2436                 */
2437                 u8 button = readU8(&data[2]);
2438                 u16 id = readS16(&data[3]);
2439                 u16 item_i = readU16(&data[11]);
2440         
2441                 ServerActiveObject *obj = m_env.getActiveObject(id);
2442
2443                 if(obj == NULL)
2444                 {
2445                         derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2446                                         <<std::endl;
2447                         return;
2448                 }
2449
2450                 // Skip if object has been removed
2451                 if(obj->m_removed)
2452                         return;
2453                 
2454                 //TODO: Check that object is reasonably close
2455                 
2456                 // Left click, pick object up (usually)
2457                 if(button == 0)
2458                 {
2459                         /*
2460                                 Try creating inventory item
2461                         */
2462                         InventoryItem *item = obj->createPickedUpItem();
2463                         
2464                         if(item)
2465                         {
2466                                 InventoryList *ilist = player->inventory.getList("main");
2467                                 if(ilist != NULL)
2468                                 {
2469                                         if(g_settings->getBool("creative_mode") == false)
2470                                         {
2471                                                 // Skip if inventory has no free space
2472                                                 if(ilist->roomForItem(item) == false)
2473                                                 {
2474                                                         dout_server<<"Player inventory has no free space"<<std::endl;
2475                                                         return;
2476                                                 }
2477
2478                                                 // Add to inventory and send inventory
2479                                                 ilist->addItem(item);
2480                                                 UpdateCrafting(player->peer_id);
2481                                                 SendInventory(player->peer_id);
2482                                         }
2483
2484                                         // Remove object from environment
2485                                         obj->m_removed = true;
2486                                 }
2487                         }
2488                         else
2489                         {
2490                                 /*
2491                                         Item cannot be picked up. Punch it instead.
2492                                 */
2493
2494                                 ToolItem *titem = NULL;
2495                                 std::string toolname = "";
2496
2497                                 InventoryList *mlist = player->inventory.getList("main");
2498                                 if(mlist != NULL)
2499                                 {
2500                                         InventoryItem *item = mlist->getItem(item_i);
2501                                         if(item && (std::string)item->getName() == "ToolItem")
2502                                         {
2503                                                 titem = (ToolItem*)item;
2504                                                 toolname = titem->getToolName();
2505                                         }
2506                                 }
2507
2508                                 v3f playerpos = player->getPosition();
2509                                 v3f objpos = obj->getBasePosition();
2510                                 v3f dir = (objpos - playerpos).normalize();
2511                                 
2512                                 u16 wear = obj->punch(toolname, dir);
2513                                 
2514                                 if(titem)
2515                                 {
2516                                         bool weared_out = titem->addWear(wear);
2517                                         if(weared_out)
2518                                                 mlist->deleteItem(item_i);
2519                                         SendInventory(player->peer_id);
2520                                 }
2521                         }
2522                 }
2523                 // Right click, do something with object
2524                 if(button == 1)
2525                 {
2526                         // Track hp changes super-crappily
2527                         u16 oldhp = player->hp;
2528                         
2529                         // Do stuff
2530                         obj->rightClick(player);
2531                         
2532                         // Send back stuff
2533                         if(player->hp != oldhp)
2534                         {
2535                                 SendPlayerHP(player);
2536                         }
2537                 }
2538         }
2539         else if(command == TOSERVER_GROUND_ACTION)
2540         {
2541                 if(datasize < 17)
2542                         return;
2543                 /*
2544                         length: 17
2545                         [0] u16 command
2546                         [2] u8 action
2547                         [3] v3s16 nodepos_undersurface
2548                         [9] v3s16 nodepos_abovesurface
2549                         [15] u16 item
2550                         actions:
2551                         0: start digging
2552                         1: place block
2553                         2: stop digging (all parameters ignored)
2554                         3: digging completed
2555                 */
2556                 u8 action = readU8(&data[2]);
2557                 v3s16 p_under;
2558                 p_under.X = readS16(&data[3]);
2559                 p_under.Y = readS16(&data[5]);
2560                 p_under.Z = readS16(&data[7]);
2561                 v3s16 p_over;
2562                 p_over.X = readS16(&data[9]);
2563                 p_over.Y = readS16(&data[11]);
2564                 p_over.Z = readS16(&data[13]);
2565                 u16 item_i = readU16(&data[15]);
2566
2567                 //TODO: Check that target is reasonably close
2568                 
2569                 /*
2570                         0: start digging
2571                 */
2572                 if(action == 0)
2573                 {
2574                         /*
2575                                 NOTE: This can be used in the future to check if
2576                                 somebody is cheating, by checking the timing.
2577                         */
2578                 } // action == 0
2579
2580                 /*
2581                         2: stop digging
2582                 */
2583                 else if(action == 2)
2584                 {
2585 #if 0
2586                         RemoteClient *client = getClient(peer->id);
2587                         JMutexAutoLock digmutex(client->m_dig_mutex);
2588                         client->m_dig_tool_item = -1;
2589 #endif
2590                 }
2591
2592                 /*
2593                         3: Digging completed
2594                 */
2595                 else if(action == 3)
2596                 {
2597                         // Mandatory parameter; actually used for nothing
2598                         core::map<v3s16, MapBlock*> modified_blocks;
2599
2600                         content_t material = CONTENT_IGNORE;
2601                         u8 mineral = MINERAL_NONE;
2602
2603                         bool cannot_remove_node = false;
2604
2605                         try
2606                         {
2607                                 MapNode n = m_env.getMap().getNode(p_under);
2608                                 // Get mineral
2609                                 mineral = n.getMineral();
2610                                 // Get material at position
2611                                 material = n.getContent();
2612                                 // If not yet cancelled
2613                                 if(cannot_remove_node == false)
2614                                 {
2615                                         // If it's not diggable, do nothing
2616                                         if(content_diggable(material) == false)
2617                                         {
2618                                                 derr_server<<"Server: Not finishing digging: "
2619                                                                 <<"Node not diggable"
2620                                                                 <<std::endl;
2621                                                 cannot_remove_node = true;
2622                                         }
2623                                 }
2624                                 // If not yet cancelled
2625                                 if(cannot_remove_node == false)
2626                                 {
2627                                         // Get node metadata
2628                                         NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2629                                         if(meta && meta->nodeRemovalDisabled() == true)
2630                                         {
2631                                                 derr_server<<"Server: Not finishing digging: "
2632                                                                 <<"Node metadata disables removal"
2633                                                                 <<std::endl;
2634                                                 cannot_remove_node = true;
2635                                         }
2636                                 }
2637                         }
2638                         catch(InvalidPositionException &e)
2639                         {
2640                                 derr_server<<"Server: Not finishing digging: Node not found."
2641                                                 <<" Adding block to emerge queue."
2642                                                 <<std::endl;
2643                                 m_emerge_queue.addBlock(peer_id,
2644                                                 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2645                                 cannot_remove_node = true;
2646                         }
2647
2648                         // Make sure the player is allowed to do it
2649                         if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2650                         {
2651                                 dstream<<"Player "<<player->getName()<<" cannot remove node"
2652                                                 <<" because privileges are "<<getPlayerPrivs(player)
2653                                                 <<std::endl;
2654                                 cannot_remove_node = true;
2655                         }
2656
2657                         /*
2658                                 If node can't be removed, set block to be re-sent to
2659                                 client and quit.
2660                         */
2661                         if(cannot_remove_node)
2662                         {
2663                                 derr_server<<"Server: Not finishing digging."<<std::endl;
2664
2665                                 // Client probably has wrong data.
2666                                 // Set block not sent, so that client will get
2667                                 // a valid one.
2668                                 dstream<<"Client "<<peer_id<<" tried to dig "
2669                                                 <<"node; but node cannot be removed."
2670                                                 <<" setting MapBlock not sent."<<std::endl;
2671                                 RemoteClient *client = getClient(peer_id);
2672                                 v3s16 blockpos = getNodeBlockPos(p_under);
2673                                 client->SetBlockNotSent(blockpos);
2674                                         
2675                                 return;
2676                         }
2677                         
2678                         /*
2679                                 Send the removal to all close-by players.
2680                                 - If other player is close, send REMOVENODE
2681                                 - Otherwise set blocks not sent
2682                         */
2683                         core::list<u16> far_players;
2684                         sendRemoveNode(p_under, peer_id, &far_players, 30);
2685                         
2686                         /*
2687                                 Update and send inventory
2688                         */
2689
2690                         if(g_settings->getBool("creative_mode") == false)
2691                         {
2692                                 /*
2693                                         Wear out tool
2694                                 */
2695                                 InventoryList *mlist = player->inventory.getList("main");
2696                                 if(mlist != NULL)
2697                                 {
2698                                         InventoryItem *item = mlist->getItem(item_i);
2699                                         if(item && (std::string)item->getName() == "ToolItem")
2700                                         {
2701                                                 ToolItem *titem = (ToolItem*)item;
2702                                                 std::string toolname = titem->getToolName();
2703
2704                                                 // Get digging properties for material and tool
2705                                                 DiggingProperties prop =
2706                                                                 getDiggingProperties(material, toolname);
2707
2708                                                 if(prop.diggable == false)
2709                                                 {
2710                                                         derr_server<<"Server: WARNING: Player digged"
2711                                                                         <<" with impossible material + tool"
2712                                                                         <<" combination"<<std::endl;
2713                                                 }
2714                                                 
2715                                                 bool weared_out = titem->addWear(prop.wear);
2716
2717                                                 if(weared_out)
2718                                                 {
2719                                                         mlist->deleteItem(item_i);
2720                                                 }
2721                                         }
2722                                 }
2723
2724                                 /*
2725                                         Add dug item to inventory
2726                                 */
2727
2728                                 InventoryItem *item = NULL;
2729
2730                                 if(mineral != MINERAL_NONE)
2731                                         item = getDiggedMineralItem(mineral);
2732                                 
2733                                 // If not mineral
2734                                 if(item == NULL)
2735                                 {
2736                                         std::string &dug_s = content_features(material).dug_item;
2737                                         if(dug_s != "")
2738                                         {
2739                                                 std::istringstream is(dug_s, std::ios::binary);
2740                                                 item = InventoryItem::deSerialize(is);
2741                                         }
2742                                 }
2743                                 
2744                                 if(item != NULL)
2745                                 {
2746                                         // Add a item to inventory
2747                                         player->inventory.addItem("main", item);
2748
2749                                         // Send inventory
2750                                         UpdateCrafting(player->peer_id);
2751                                         SendInventory(player->peer_id);
2752                                 }
2753
2754                                 item = NULL;
2755
2756                                 if(mineral != MINERAL_NONE)
2757                                   item = getDiggedMineralItem(mineral);
2758                         
2759                                 // If not mineral
2760                                 if(item == NULL)
2761                                 {
2762                                         std::string &extra_dug_s = content_features(material).extra_dug_item;
2763                                         s32 extra_rarity = content_features(material).extra_dug_item_rarity;
2764                                         if(extra_dug_s != "" && extra_rarity != 0
2765                                            && myrand() % extra_rarity == 0)
2766                                         {
2767                                                 std::istringstream is(extra_dug_s, std::ios::binary);
2768                                                 item = InventoryItem::deSerialize(is);
2769                                         }
2770                                 }
2771                         
2772                                 if(item != NULL)
2773                                 {
2774                                         // Add a item to inventory
2775                                         player->inventory.addItem("main", item);
2776
2777                                         // Send inventory
2778                                         UpdateCrafting(player->peer_id);
2779                                         SendInventory(player->peer_id);
2780                                 }
2781                         }
2782
2783                         /*
2784                                 Remove the node
2785                                 (this takes some time so it is done after the quick stuff)
2786                         */
2787                         {
2788                                 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2789
2790                                 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2791                         }
2792                         /*
2793                                 Set blocks not sent to far players
2794                         */
2795                         for(core::list<u16>::Iterator
2796                                         i = far_players.begin();
2797                                         i != far_players.end(); i++)
2798                         {
2799                                 u16 peer_id = *i;
2800                                 RemoteClient *client = getClient(peer_id);
2801                                 if(client==NULL)
2802                                         continue;
2803                                 client->SetBlocksNotSent(modified_blocks);
2804                         }
2805                 }
2806                 
2807                 /*
2808                         1: place block
2809                 */
2810                 else if(action == 1)
2811                 {
2812
2813                         InventoryList *ilist = player->inventory.getList("main");
2814                         if(ilist == NULL)
2815                                 return;
2816
2817                         // Get item
2818                         InventoryItem *item = ilist->getItem(item_i);
2819                         
2820                         // If there is no item, it is not possible to add it anywhere
2821                         if(item == NULL)
2822                                 return;
2823                         
2824                         /*
2825                                 Handle material items
2826                         */
2827                         if(std::string("MaterialItem") == item->getName())
2828                         {
2829                                 try{
2830                                         // Don't add a node if this is not a free space
2831                                         MapNode n2 = m_env.getMap().getNode(p_over);
2832                                         bool no_enough_privs =
2833                                                         ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2834                                         if(no_enough_privs)
2835                                                 dstream<<"Player "<<player->getName()<<" cannot add node"
2836                                                         <<" because privileges are "<<getPlayerPrivs(player)
2837                                                         <<std::endl;
2838
2839                                         if(content_features(n2).buildable_to == false
2840                                                 || no_enough_privs)
2841                                         {
2842                                                 // Client probably has wrong data.
2843                                                 // Set block not sent, so that client will get
2844                                                 // a valid one.
2845                                                 dstream<<"Client "<<peer_id<<" tried to place"
2846                                                                 <<" node in invalid position; setting"
2847                                                                 <<" MapBlock not sent."<<std::endl;
2848                                                 RemoteClient *client = getClient(peer_id);
2849                                                 v3s16 blockpos = getNodeBlockPos(p_over);
2850                                                 client->SetBlockNotSent(blockpos);
2851                                                 return;
2852                                         }
2853                                 }
2854                                 catch(InvalidPositionException &e)
2855                                 {
2856                                         derr_server<<"Server: Ignoring ADDNODE: Node not found"
2857                                                         <<" Adding block to emerge queue."
2858                                                         <<std::endl;
2859                                         m_emerge_queue.addBlock(peer_id,
2860                                                         getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2861                                         return;
2862                                 }
2863
2864                                 // Reset build time counter
2865                                 getClient(peer->id)->m_time_from_building = 0.0;
2866                                 
2867                                 // Create node data
2868                                 MaterialItem *mitem = (MaterialItem*)item;
2869                                 MapNode n;
2870                                 n.setContent(mitem->getMaterial());
2871
2872                                 // Calculate direction for wall mounted stuff
2873                                 if(content_features(n).wall_mounted)
2874                                         n.param2 = packDir(p_under - p_over);
2875
2876                                 // Calculate the direction for furnaces and chests and stuff
2877                                 if(content_features(n).param_type == CPT_FACEDIR_SIMPLE)
2878                                 {
2879                                         v3f playerpos = player->getPosition();
2880                                         v3f blockpos = intToFloat(p_over, BS) - playerpos;
2881                                         blockpos = blockpos.normalize();
2882                                         n.param1 = 0;
2883                                         if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2884                                                 if (blockpos.X < 0)
2885                                                         n.param1 = 3;
2886                                                 else
2887                                                         n.param1 = 1;
2888                                         } else {
2889                                                 if (blockpos.Z < 0)
2890                                                         n.param1 = 2;
2891                                                 else
2892                                                         n.param1 = 0;
2893                                         }
2894                                 }
2895
2896                                 /*
2897                                         Send to all close-by players
2898                                 */
2899                                 core::list<u16> far_players;
2900                                 sendAddNode(p_over, n, 0, &far_players, 30);
2901                                 
2902                                 /*
2903                                         Handle inventory
2904                                 */
2905                                 InventoryList *ilist = player->inventory.getList("main");
2906                                 if(g_settings->getBool("creative_mode") == false && ilist)
2907                                 {
2908                                         // Remove from inventory and send inventory
2909                                         if(mitem->getCount() == 1)
2910                                                 ilist->deleteItem(item_i);
2911                                         else
2912                                                 mitem->remove(1);
2913                                         // Send inventory
2914                                         UpdateCrafting(peer_id);
2915                                         SendInventory(peer_id);
2916                                 }
2917                                 
2918                                 /*
2919                                         Add node.
2920
2921                                         This takes some time so it is done after the quick stuff
2922                                 */
2923                                 core::map<v3s16, MapBlock*> modified_blocks;
2924                                 {
2925                                         MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2926
2927                                         std::string p_name = std::string(player->getName());
2928                                         m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name);
2929                                 }
2930                                 /*
2931                                         Set blocks not sent to far players
2932                                 */
2933                                 for(core::list<u16>::Iterator
2934                                                 i = far_players.begin();
2935                                                 i != far_players.end(); i++)
2936                                 {
2937                                         u16 peer_id = *i;
2938                                         RemoteClient *client = getClient(peer_id);
2939                                         if(client==NULL)
2940                                                 continue;
2941                                         client->SetBlocksNotSent(modified_blocks);
2942                                 }
2943
2944                                 /*
2945                                         Calculate special events
2946                                 */
2947                                 
2948                                 /*if(n.d == CONTENT_MESE)
2949                                 {
2950                                         u32 count = 0;
2951                                         for(s16 z=-1; z<=1; z++)
2952                                         for(s16 y=-1; y<=1; y++)
2953                                         for(s16 x=-1; x<=1; x++)
2954                                         {
2955                                                 
2956                                         }
2957                                 }*/
2958                         }
2959                         /*
2960                                 Place other item (not a block)
2961                         */
2962                         else
2963                         {
2964                                 v3s16 blockpos = getNodeBlockPos(p_over);
2965                                 
2966                                 /*
2967                                         Check that the block is loaded so that the item
2968                                         can properly be added to the static list too
2969                                 */
2970                                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2971                                 if(block==NULL)
2972                                 {
2973                                         derr_server<<"Error while placing object: "
2974                                                         "block not found"<<std::endl;
2975                                         return;
2976                                 }
2977
2978                                 /*
2979                                         If in creative mode, item dropping is disabled unless
2980                                         player has build privileges
2981                                 */
2982                                 if(g_settings->getBool("creative_mode") &&
2983                                         (getPlayerPrivs(player) & PRIV_BUILD) == 0)
2984                                 {
2985                                         derr_server<<"Not allowing player to drop item: "
2986                                                         "creative mode and no build privs"<<std::endl;
2987                                         return;
2988                                 }
2989
2990                                 dout_server<<"Placing a miscellaneous item on map"
2991                                                 <<std::endl;
2992                                 
2993                                 // Calculate a position for it
2994                                 v3f pos = intToFloat(p_over, BS);
2995                                 //pos.Y -= BS*0.45;
2996                                 pos.Y -= BS*0.25; // let it drop a bit
2997                                 // Randomize a bit
2998                                 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2999                                 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
3000
3001                                 /*
3002                                         Create the object
3003                                 */
3004                                 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
3005
3006                                 if(obj == NULL)
3007                                 {
3008                                         derr_server<<"WARNING: item resulted in NULL object, "
3009                                                         <<"not placing onto map"
3010                                                         <<std::endl;
3011                                 }
3012                                 else
3013                                 {
3014                                         // Add the object to the environment
3015                                         m_env.addActiveObject(obj);
3016                                         
3017                                         dout_server<<"Placed object"<<std::endl;
3018
3019                                         if(g_settings->getBool("creative_mode") == false)
3020                                         {
3021                                                 // Delete the right amount of items from the slot
3022                                                 u16 dropcount = item->getDropCount();
3023                                                 
3024                                                 // Delete item if all gone
3025                                                 if(item->getCount() <= dropcount)
3026                                                 {
3027                                                         if(item->getCount() < dropcount)
3028                                                                 dstream<<"WARNING: Server: dropped more items"
3029                                                                                 <<" than the slot contains"<<std::endl;
3030                                                         
3031                                                         InventoryList *ilist = player->inventory.getList("main");
3032                                                         if(ilist)
3033                                                                 // Remove from inventory and send inventory
3034                                                                 ilist->deleteItem(item_i);
3035                                                 }
3036                                                 // Else decrement it
3037                                                 else
3038                                                         item->remove(dropcount);
3039                                                 
3040                                                 // Send inventory
3041                                                 UpdateCrafting(peer_id);
3042                                                 SendInventory(peer_id);
3043                                         }
3044                                 }
3045                         }
3046
3047                 } // action == 1
3048
3049                 /*
3050                         Catch invalid actions
3051                 */
3052                 else
3053                 {
3054                         derr_server<<"WARNING: Server: Invalid action "
3055                                         <<action<<std::endl;
3056                 }
3057         }
3058 #if 0
3059         else if(command == TOSERVER_RELEASE)
3060         {
3061                 if(datasize < 3)
3062                         return;
3063                 /*
3064                         length: 3
3065                         [0] u16 command
3066                         [2] u8 button
3067                 */
3068                 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
3069         }
3070 #endif
3071         else if(command == TOSERVER_SIGNTEXT)
3072         {
3073                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3074                         return;
3075                 /*
3076                         u16 command
3077                         v3s16 blockpos
3078                         s16 id
3079                         u16 textlen
3080                         textdata
3081                 */
3082                 std::string datastring((char*)&data[2], datasize-2);
3083                 std::istringstream is(datastring, std::ios_base::binary);
3084                 u8 buf[6];
3085                 // Read stuff
3086                 is.read((char*)buf, 6);
3087                 v3s16 blockpos = readV3S16(buf);
3088                 is.read((char*)buf, 2);
3089                 s16 id = readS16(buf);
3090                 is.read((char*)buf, 2);
3091                 u16 textlen = readU16(buf);
3092                 std::string text;
3093                 for(u16 i=0; i<textlen; i++)
3094                 {
3095                         is.read((char*)buf, 1);
3096                         text += (char)buf[0];
3097                 }
3098
3099                 MapBlock *block = NULL;
3100                 try
3101                 {
3102                         block = m_env.getMap().getBlockNoCreate(blockpos);
3103                 }
3104                 catch(InvalidPositionException &e)
3105                 {
3106                         derr_server<<"Error while setting sign text: "
3107                                         "block not found"<<std::endl;
3108                         return;
3109                 }
3110
3111                 MapBlockObject *obj = block->getObject(id);
3112                 if(obj == NULL)
3113                 {
3114                         derr_server<<"Error while setting sign text: "
3115                                         "object not found"<<std::endl;
3116                         return;
3117                 }
3118                 
3119                 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
3120                 {
3121                         derr_server<<"Error while setting sign text: "
3122                                         "object is not a sign"<<std::endl;
3123                         return;
3124                 }
3125
3126                 ((SignObject*)obj)->setText(text);
3127
3128                 obj->getBlock()->setChangedFlag();
3129         }
3130         else if(command == TOSERVER_SIGNNODETEXT)
3131         {
3132                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3133                         return;
3134                 /*
3135                         u16 command
3136                         v3s16 p
3137                         u16 textlen
3138                         textdata
3139                 */
3140                 std::string datastring((char*)&data[2], datasize-2);
3141                 std::istringstream is(datastring, std::ios_base::binary);
3142                 u8 buf[6];
3143                 // Read stuff
3144                 is.read((char*)buf, 6);
3145                 v3s16 p = readV3S16(buf);
3146                 is.read((char*)buf, 2);
3147                 u16 textlen = readU16(buf);
3148                 std::string text;
3149                 for(u16 i=0; i<textlen; i++)
3150                 {
3151                         is.read((char*)buf, 1);
3152                         text += (char)buf[0];
3153                 }
3154
3155                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3156                 if(!meta)
3157                         return;
3158                 if(meta->typeId() != CONTENT_SIGN_WALL)
3159                         return;
3160                 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
3161                 signmeta->setText(text);
3162                 
3163                 v3s16 blockpos = getNodeBlockPos(p);
3164                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
3165                 if(block)
3166                 {
3167                         block->setChangedFlag();
3168                 }
3169
3170                 for(core::map<u16, RemoteClient*>::Iterator
3171                         i = m_clients.getIterator();
3172                         i.atEnd()==false; i++)
3173                 {
3174                         RemoteClient *client = i.getNode()->getValue();
3175                         client->SetBlockNotSent(blockpos);
3176                 }
3177         }
3178         else if(command == TOSERVER_INVENTORY_ACTION)
3179         {
3180                 /*// Ignore inventory changes if in creative mode
3181                 if(g_settings->getBool("creative_mode") == true)
3182                 {
3183                         dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3184                                         <<std::endl;
3185                         return;
3186                 }*/
3187                 // Strip command and create a stream
3188                 std::string datastring((char*)&data[2], datasize-2);
3189                 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3190                 std::istringstream is(datastring, std::ios_base::binary);
3191                 // Create an action
3192                 InventoryAction *a = InventoryAction::deSerialize(is);
3193                 if(a != NULL)
3194                 {
3195                         // Create context
3196                         InventoryContext c;
3197                         c.current_player = player;
3198
3199                         /*
3200                                 Handle craftresult specially if not in creative mode
3201                         */
3202                         bool disable_action = false;
3203                         if(a->getType() == IACTION_MOVE
3204                                         && g_settings->getBool("creative_mode") == false)
3205                         {
3206                                 IMoveAction *ma = (IMoveAction*)a;
3207                                 if(ma->to_inv == "current_player" &&
3208                                                 ma->from_inv == "current_player")
3209                                 {
3210                                         InventoryList *rlist = player->inventory.getList("craftresult");
3211                                         assert(rlist);
3212                                         InventoryList *clist = player->inventory.getList("craft");
3213                                         assert(clist);
3214                                         InventoryList *mlist = player->inventory.getList("main");
3215                                         assert(mlist);
3216                                         /*
3217                                                 Craftresult is no longer preview if something
3218                                                 is moved into it
3219                                         */
3220                                         if(ma->to_list == "craftresult"
3221                                                         && ma->from_list != "craftresult")
3222                                         {
3223                                                 // If it currently is a preview, remove
3224                                                 // its contents
3225                                                 if(player->craftresult_is_preview)
3226                                                 {
3227                                                         rlist->deleteItem(0);
3228                                                 }
3229                                                 player->craftresult_is_preview = false;
3230                                         }
3231                                         /*
3232                                                 Crafting takes place if this condition is true.
3233                                         */
3234                                         if(player->craftresult_is_preview &&
3235                                                         ma->from_list == "craftresult")
3236                                         {
3237                                                 player->craftresult_is_preview = false;
3238                                                 clist->decrementMaterials(1);
3239                                         }
3240                                         /*
3241                                                 If the craftresult is placed on itself, move it to
3242                                                 main inventory instead of doing the action
3243                                         */
3244                                         if(ma->to_list == "craftresult"
3245                                                         && ma->from_list == "craftresult")
3246                                         {
3247                                                 disable_action = true;
3248                                                 
3249                                                 InventoryItem *item1 = rlist->changeItem(0, NULL);
3250                                                 mlist->addItem(item1);
3251                                         }
3252                                 }
3253                                 // Disallow moving items if not allowed to build
3254                                 else if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3255                                 {
3256                                         return;
3257                                 }
3258                                 // if it's a locking chest, only allow the owner or server admins to move items
3259                                 else if (ma->from_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3260                                 {
3261                                         Strfnd fn(ma->from_inv);
3262                                         std::string id0 = fn.next(":");
3263                                         if(id0 == "nodemeta")
3264                                         {
3265                                                 v3s16 p;
3266                                                 p.X = stoi(fn.next(","));
3267                                                 p.Y = stoi(fn.next(","));
3268                                                 p.Z = stoi(fn.next(","));
3269                                                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3270                                                 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3271                                                         LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3272                                                         if (lcm->getOwner() != player->getName())
3273                                                                 return;
3274                                                 }
3275                                         }
3276                                 }
3277                                 else if (ma->to_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3278                                 {
3279                                         Strfnd fn(ma->to_inv);
3280                                         std::string id0 = fn.next(":");
3281                                         if(id0 == "nodemeta")
3282                                         {
3283                                                 v3s16 p;
3284                                                 p.X = stoi(fn.next(","));
3285                                                 p.Y = stoi(fn.next(","));
3286                                                 p.Z = stoi(fn.next(","));
3287                                                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3288                                                 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3289                                                         LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3290                                                         if (lcm->getOwner() != player->getName())
3291                                                                 return;
3292                                                 }
3293                                         }
3294                                 }
3295                         }
3296                         
3297                         if(disable_action == false)
3298                         {
3299                                 // Feed action to player inventory
3300                                 a->apply(&c, this);
3301                                 // Eat the action
3302                                 delete a;
3303                         }
3304                         else
3305                         {
3306                                 // Send inventory
3307                                 UpdateCrafting(player->peer_id);
3308                                 SendInventory(player->peer_id);
3309                         }
3310                 }
3311                 else
3312                 {
3313                         dstream<<"TOSERVER_INVENTORY_ACTION: "
3314                                         <<"InventoryAction::deSerialize() returned NULL"
3315                                         <<std::endl;
3316                 }
3317         }
3318         else if(command == TOSERVER_CHAT_MESSAGE)
3319         {
3320                 /*
3321                         u16 command
3322                         u16 length
3323                         wstring message
3324                 */
3325                 u8 buf[6];
3326                 std::string datastring((char*)&data[2], datasize-2);
3327                 std::istringstream is(datastring, std::ios_base::binary);
3328                 
3329                 // Read stuff
3330                 is.read((char*)buf, 2);
3331                 u16 len = readU16(buf);
3332                 
3333                 std::wstring message;
3334                 for(u16 i=0; i<len; i++)
3335                 {
3336                         is.read((char*)buf, 2);
3337                         message += (wchar_t)readU16(buf);
3338                 }
3339
3340                 // Get player name of this client
3341                 std::wstring name = narrow_to_wide(player->getName());
3342                 
3343                 // Line to send to players
3344                 std::wstring line;
3345                 // Whether to send to the player that sent the line
3346                 bool send_to_sender = false;
3347                 // Whether to send to other players
3348                 bool send_to_others = false;
3349                 
3350                 // Local player gets all privileges regardless of
3351                 // what's set on their account.
3352                 u64 privs = getPlayerPrivs(player);
3353
3354                 // Parse commands
3355                 if(message[0] == L'/')
3356                 {
3357                         size_t strip_size = 1;
3358                         if (message[1] == L'#') // support old-style commans
3359                                 ++strip_size;
3360                         message = message.substr(strip_size);
3361
3362                         WStrfnd f1(message);
3363                         f1.next(L" "); // Skip over /#whatever
3364                         std::wstring paramstring = f1.next(L"");
3365
3366                         ServerCommandContext *ctx = new ServerCommandContext(
3367                                 str_split(message, L' '),
3368                                 paramstring,
3369                                 this,
3370                                 &m_env,
3371                                 player,
3372                                 privs);
3373
3374                         std::wstring reply(processServerCommand(ctx));
3375                         send_to_sender = ctx->flags & SEND_TO_SENDER;
3376                         send_to_others = ctx->flags & SEND_TO_OTHERS;
3377
3378                         if (ctx->flags & SEND_NO_PREFIX)
3379                                 line += reply;
3380                         else
3381                                 line += L"Server: " + reply;
3382
3383                         delete ctx;
3384
3385                 }
3386                 else
3387                 {
3388                         if(privs & PRIV_SHOUT)
3389                         {
3390                                 line += L"<";
3391                                 line += name;
3392                                 line += L"> ";
3393                                 line += message;
3394                                 send_to_others = true;
3395                         }
3396                         else
3397                         {
3398                                 line += L"Server: You are not allowed to shout";
3399                                 send_to_sender = true;
3400                         }
3401                 }
3402                 
3403                 if(line != L"")
3404                 {
3405                         dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3406
3407                         /*
3408                                 Send the message to clients
3409                         */
3410                         for(core::map<u16, RemoteClient*>::Iterator
3411                                 i = m_clients.getIterator();
3412                                 i.atEnd() == false; i++)
3413                         {
3414                                 // Get client and check that it is valid
3415                                 RemoteClient *client = i.getNode()->getValue();
3416                                 assert(client->peer_id == i.getNode()->getKey());
3417                                 if(client->serialization_version == SER_FMT_VER_INVALID)
3418                                         continue;
3419
3420                                 // Filter recipient
3421                                 bool sender_selected = (peer_id == client->peer_id);
3422                                 if(sender_selected == true && send_to_sender == false)
3423                                         continue;
3424                                 if(sender_selected == false && send_to_others == false)
3425                                         continue;
3426
3427                                 SendChatMessage(client->peer_id, line);
3428                         }
3429                 }
3430         }
3431         else if(command == TOSERVER_DAMAGE)
3432         {
3433                 if(g_settings->getBool("enable_damage"))
3434                 {
3435                         std::string datastring((char*)&data[2], datasize-2);
3436                         std::istringstream is(datastring, std::ios_base::binary);
3437                         u8 damage = readU8(is);
3438                         if(player->hp > damage)
3439                         {
3440                                 player->hp -= damage;
3441                         }
3442                         else
3443                         {
3444                                 player->hp = 0;
3445
3446                                 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3447                                                 <<std::endl;
3448                                 
3449                                 v3f pos = findSpawnPos(m_env.getServerMap());
3450                                 player->setPosition(pos);
3451                                 player->hp = 20;
3452                                 SendMovePlayer(player);
3453                                 SendPlayerHP(player);
3454                                 
3455                                 //TODO: Throw items around
3456                         }
3457                 }
3458
3459                 SendPlayerHP(player);
3460         }
3461         else if(command == TOSERVER_PASSWORD)
3462         {
3463                 /*
3464                         [0] u16 TOSERVER_PASSWORD
3465                         [2] u8[28] old password
3466                         [30] u8[28] new password
3467                 */
3468
3469                 if(datasize != 2+PASSWORD_SIZE*2)
3470                         return;
3471                 /*char password[PASSWORD_SIZE];
3472                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3473                         password[i] = data[2+i];
3474                 password[PASSWORD_SIZE-1] = 0;*/
3475                 std::string oldpwd;
3476                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3477                 {
3478                         char c = data[2+i];
3479                         if(c == 0)
3480                                 break;
3481                         oldpwd += c;
3482                 }
3483                 std::string newpwd;
3484                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3485                 {
3486                         char c = data[2+PASSWORD_SIZE+i];
3487                         if(c == 0)
3488                                 break;
3489                         newpwd += c;
3490                 }
3491
3492                 dstream<<"Server: Client requests a password change from "
3493                                 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
3494
3495                 std::string playername = player->getName();
3496
3497                 if(m_authmanager.exists(playername) == false)
3498                 {
3499                         dstream<<"Server: playername not found in authmanager"<<std::endl;
3500                         // Wrong old password supplied!!
3501                         SendChatMessage(peer_id, L"playername not found in authmanager");
3502                         return;
3503                 }
3504
3505                 std::string checkpwd = m_authmanager.getPassword(playername);
3506
3507                 if(oldpwd != checkpwd)
3508                 {
3509                         dstream<<"Server: invalid old password"<<std::endl;
3510                         // Wrong old password supplied!!
3511                         SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3512                         return;
3513                 }
3514
3515                 m_authmanager.setPassword(playername, newpwd);
3516                 
3517                 dstream<<"Server: password change successful for "<<playername
3518                                 <<std::endl;
3519                 SendChatMessage(peer_id, L"Password change successful");
3520         }
3521         else if (command == TOSERVER_PLAYERITEM)
3522         {
3523                 if (datasize < 2+2)
3524                         return;
3525
3526                 u16 item = readU16(&data[2]);
3527                 player->wieldItem(item);
3528                 SendWieldedItem(player);
3529         }
3530         else
3531         {
3532                 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3533                                 "unknown command "<<command<<std::endl;
3534         }
3535         
3536         } //try
3537         catch(SendFailedException &e)
3538         {
3539                 derr_server<<"Server::ProcessData(): SendFailedException: "
3540                                 <<"what="<<e.what()
3541                                 <<std::endl;
3542         }
3543 }
3544
3545 void Server::onMapEditEvent(MapEditEvent *event)
3546 {
3547         //dstream<<"Server::onMapEditEvent()"<<std::endl;
3548         if(m_ignore_map_edit_events)
3549                 return;
3550         MapEditEvent *e = event->clone();
3551         m_unsent_map_edit_queue.push_back(e);
3552 }
3553
3554 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3555 {
3556         if(id == "current_player")
3557         {
3558                 assert(c->current_player);
3559                 return &(c->current_player->inventory);
3560         }
3561         
3562         Strfnd fn(id);
3563         std::string id0 = fn.next(":");
3564
3565         if(id0 == "nodemeta")
3566         {
3567                 v3s16 p;
3568                 p.X = stoi(fn.next(","));
3569                 p.Y = stoi(fn.next(","));
3570                 p.Z = stoi(fn.next(","));
3571                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3572                 if(meta)
3573                         return meta->getInventory();
3574                 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3575                                 <<"no metadata found"<<std::endl;
3576                 return NULL;
3577         }
3578
3579         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3580         return NULL;
3581 }
3582 void Server::inventoryModified(InventoryContext *c, std::string id)
3583 {
3584         if(id == "current_player")
3585         {
3586                 assert(c->current_player);
3587                 // Send inventory
3588                 UpdateCrafting(c->current_player->peer_id);
3589                 SendInventory(c->current_player->peer_id);
3590                 return;
3591         }
3592         
3593         Strfnd fn(id);
3594         std::string id0 = fn.next(":");
3595
3596         if(id0 == "nodemeta")
3597         {
3598                 v3s16 p;
3599                 p.X = stoi(fn.next(","));
3600                 p.Y = stoi(fn.next(","));
3601                 p.Z = stoi(fn.next(","));
3602                 v3s16 blockpos = getNodeBlockPos(p);
3603
3604                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3605                 if(meta)
3606                         meta->inventoryModified();
3607
3608                 for(core::map<u16, RemoteClient*>::Iterator
3609                         i = m_clients.getIterator();
3610                         i.atEnd()==false; i++)
3611                 {
3612                         RemoteClient *client = i.getNode()->getValue();
3613                         client->SetBlockNotSent(blockpos);
3614                 }
3615
3616                 return;
3617         }
3618
3619         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3620 }
3621
3622 core::list<PlayerInfo> Server::getPlayerInfo()
3623 {
3624         DSTACK(__FUNCTION_NAME);
3625         JMutexAutoLock envlock(m_env_mutex);
3626         JMutexAutoLock conlock(m_con_mutex);
3627         
3628         core::list<PlayerInfo> list;
3629
3630         core::list<Player*> players = m_env.getPlayers();
3631         
3632         core::list<Player*>::Iterator i;
3633         for(i = players.begin();
3634                         i != players.end(); i++)
3635         {
3636                 PlayerInfo info;
3637
3638                 Player *player = *i;
3639
3640                 try{
3641                         con::Peer *peer = m_con.GetPeer(player->peer_id);
3642                         // Copy info from peer to info struct
3643                         info.id = peer->id;
3644                         info.address = peer->address;
3645                         info.avg_rtt = peer->avg_rtt;
3646                 }
3647                 catch(con::PeerNotFoundException &e)
3648                 {
3649                         // Set dummy peer info
3650                         info.id = 0;
3651                         info.address = Address(0,0,0,0,0);
3652                         info.avg_rtt = 0.0;
3653                 }
3654
3655                 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3656                 info.position = player->getPosition();
3657
3658                 list.push_back(info);
3659         }
3660
3661         return list;
3662 }
3663
3664
3665 void Server::peerAdded(con::Peer *peer)
3666 {
3667         DSTACK(__FUNCTION_NAME);
3668         dout_server<<"Server::peerAdded(): peer->id="
3669                         <<peer->id<<std::endl;
3670         
3671         PeerChange c;
3672         c.type = PEER_ADDED;
3673         c.peer_id = peer->id;
3674         c.timeout = false;
3675         m_peer_change_queue.push_back(c);
3676 }
3677
3678 void Server::deletingPeer(con::Peer *peer, bool timeout)
3679 {
3680         DSTACK(__FUNCTION_NAME);
3681         dout_server<<"Server::deletingPeer(): peer->id="
3682                         <<peer->id<<", timeout="<<timeout<<std::endl;
3683         
3684         PeerChange c;
3685         c.type = PEER_REMOVED;
3686         c.peer_id = peer->id;
3687         c.timeout = timeout;
3688         m_peer_change_queue.push_back(c);
3689 }
3690
3691 /*
3692         Static send methods
3693 */
3694
3695 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3696 {
3697         DSTACK(__FUNCTION_NAME);
3698         std::ostringstream os(std::ios_base::binary);
3699
3700         writeU16(os, TOCLIENT_HP);
3701         writeU8(os, hp);
3702
3703         // Make data buffer
3704         std::string s = os.str();
3705         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3706         // Send as reliable
3707         con.Send(peer_id, 0, data, true);
3708 }
3709
3710 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3711                 const std::wstring &reason)
3712 {
3713         DSTACK(__FUNCTION_NAME);
3714         std::ostringstream os(std::ios_base::binary);
3715
3716         writeU16(os, TOCLIENT_ACCESS_DENIED);
3717         os<<serializeWideString(reason);
3718
3719         // Make data buffer
3720         std::string s = os.str();
3721         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3722         // Send as reliable
3723         con.Send(peer_id, 0, data, true);
3724 }
3725
3726 /*
3727         Non-static send methods
3728 */
3729
3730 void Server::SendObjectData(float dtime)
3731 {
3732         DSTACK(__FUNCTION_NAME);
3733
3734         core::map<v3s16, bool> stepped_blocks;
3735         
3736         for(core::map<u16, RemoteClient*>::Iterator
3737                 i = m_clients.getIterator();
3738                 i.atEnd() == false; i++)
3739         {
3740                 u16 peer_id = i.getNode()->getKey();
3741                 RemoteClient *client = i.getNode()->getValue();
3742                 assert(client->peer_id == peer_id);
3743                 
3744                 if(client->serialization_version == SER_FMT_VER_INVALID)
3745                         continue;
3746                 
3747                 client->SendObjectData(this, dtime, stepped_blocks);
3748         }
3749 }
3750
3751 void Server::SendPlayerInfos()
3752 {
3753         DSTACK(__FUNCTION_NAME);
3754
3755         //JMutexAutoLock envlock(m_env_mutex);
3756         
3757         // Get connected players
3758         core::list<Player*> players = m_env.getPlayers(true);
3759         
3760         u32 player_count = players.getSize();
3761         u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3762
3763         SharedBuffer<u8> data(datasize);
3764         writeU16(&data[0], TOCLIENT_PLAYERINFO);
3765         
3766         u32 start = 2;
3767         core::list<Player*>::Iterator i;
3768         for(i = players.begin();
3769                         i != players.end(); i++)
3770         {
3771                 Player *player = *i;
3772
3773                 /*dstream<<"Server sending player info for player with "
3774                                 "peer_id="<<player->peer_id<<std::endl;*/
3775                 
3776                 writeU16(&data[start], player->peer_id);
3777                 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3778                 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3779                 start += 2+PLAYERNAME_SIZE;
3780         }
3781
3782         //JMutexAutoLock conlock(m_con_mutex);
3783
3784         // Send as reliable
3785         m_con.SendToAll(0, data, true);
3786 }
3787
3788 void Server::SendInventory(u16 peer_id)
3789 {
3790         DSTACK(__FUNCTION_NAME);
3791         
3792         Player* player = m_env.getPlayer(peer_id);
3793         assert(player);
3794
3795         /*
3796                 Serialize it
3797         */
3798
3799         std::ostringstream os;
3800         //os.imbue(std::locale("C"));
3801
3802         player->inventory.serialize(os);
3803
3804         std::string s = os.str();
3805         
3806         SharedBuffer<u8> data(s.size()+2);
3807         writeU16(&data[0], TOCLIENT_INVENTORY);
3808         memcpy(&data[2], s.c_str(), s.size());
3809         
3810         // Send as reliable
3811         m_con.Send(peer_id, 0, data, true);
3812 }
3813
3814 std::string getWieldedItemString(const Player *player)
3815 {
3816         const InventoryItem *item = player->getWieldItem();
3817         if (item == NULL)
3818                 return std::string("");
3819         std::ostringstream os(std::ios_base::binary);
3820         item->serialize(os);
3821         return os.str();
3822 }
3823
3824 void Server::SendWieldedItem(const Player* player)
3825 {
3826         DSTACK(__FUNCTION_NAME);
3827
3828         assert(player);
3829
3830         std::ostringstream os(std::ios_base::binary);
3831
3832         writeU16(os, TOCLIENT_PLAYERITEM);
3833         writeU16(os, 1);
3834         writeU16(os, player->peer_id);
3835         os<<serializeString(getWieldedItemString(player));
3836
3837         // Make data buffer
3838         std::string s = os.str();
3839         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3840
3841         m_con.SendToAll(0, data, true);
3842 }
3843
3844 void Server::SendPlayerItems()
3845 {
3846         DSTACK(__FUNCTION_NAME);
3847
3848         std::ostringstream os(std::ios_base::binary);
3849         core::list<Player *> players = m_env.getPlayers(true);
3850
3851         writeU16(os, TOCLIENT_PLAYERITEM);
3852         writeU16(os, players.size());
3853         core::list<Player *>::Iterator i;
3854         for(i = players.begin(); i != players.end(); ++i)
3855         {
3856                 Player *p = *i;
3857                 writeU16(os, p->peer_id);
3858                 os<<serializeString(getWieldedItemString(p));
3859         }
3860
3861         // Make data buffer
3862         std::string s = os.str();
3863         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3864
3865         m_con.SendToAll(0, data, true);
3866 }
3867
3868 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3869 {
3870         DSTACK(__FUNCTION_NAME);
3871         
3872         std::ostringstream os(std::ios_base::binary);
3873         u8 buf[12];
3874         
3875         // Write command
3876         writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3877         os.write((char*)buf, 2);
3878         
3879         // Write length
3880         writeU16(buf, message.size());
3881         os.write((char*)buf, 2);
3882         
3883         // Write string
3884         for(u32 i=0; i<message.size(); i++)
3885         {
3886                 u16 w = message[i];
3887                 writeU16(buf, w);
3888                 os.write((char*)buf, 2);
3889         }
3890         
3891         // Make data buffer
3892         std::string s = os.str();
3893         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3894         // Send as reliable
3895         m_con.Send(peer_id, 0, data, true);
3896 }
3897
3898 void Server::BroadcastChatMessage(const std::wstring &message)
3899 {
3900         for(core::map<u16, RemoteClient*>::Iterator
3901                 i = m_clients.getIterator();
3902                 i.atEnd() == false; i++)
3903         {
3904                 // Get client and check that it is valid
3905                 RemoteClient *client = i.getNode()->getValue();
3906                 assert(client->peer_id == i.getNode()->getKey());
3907                 if(client->serialization_version == SER_FMT_VER_INVALID)
3908                         continue;
3909
3910                 SendChatMessage(client->peer_id, message);
3911         }
3912 }
3913
3914 void Server::SendPlayerHP(Player *player)
3915 {
3916         SendHP(m_con, player->peer_id, player->hp);
3917 }
3918
3919 void Server::SendMovePlayer(Player *player)
3920 {
3921         DSTACK(__FUNCTION_NAME);
3922         std::ostringstream os(std::ios_base::binary);
3923
3924         writeU16(os, TOCLIENT_MOVE_PLAYER);
3925         writeV3F1000(os, player->getPosition());
3926         writeF1000(os, player->getPitch());
3927         writeF1000(os, player->getYaw());
3928         
3929         {
3930                 v3f pos = player->getPosition();
3931                 f32 pitch = player->getPitch();
3932                 f32 yaw = player->getYaw();
3933                 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3934                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3935                                 <<" pitch="<<pitch
3936                                 <<" yaw="<<yaw
3937                                 <<std::endl;
3938         }
3939
3940         // Make data buffer
3941         std::string s = os.str();
3942         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3943         // Send as reliable
3944         m_con.Send(player->peer_id, 0, data, true);
3945 }
3946
3947 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3948         core::list<u16> *far_players, float far_d_nodes)
3949 {
3950         float maxd = far_d_nodes*BS;
3951         v3f p_f = intToFloat(p, BS);
3952
3953         // Create packet
3954         u32 replysize = 8;
3955         SharedBuffer<u8> reply(replysize);
3956         writeU16(&reply[0], TOCLIENT_REMOVENODE);
3957         writeS16(&reply[2], p.X);
3958         writeS16(&reply[4], p.Y);
3959         writeS16(&reply[6], p.Z);
3960
3961         for(core::map<u16, RemoteClient*>::Iterator
3962                 i = m_clients.getIterator();
3963                 i.atEnd() == false; i++)
3964         {
3965                 // Get client and check that it is valid
3966                 RemoteClient *client = i.getNode()->getValue();
3967                 assert(client->peer_id == i.getNode()->getKey());
3968                 if(client->serialization_version == SER_FMT_VER_INVALID)
3969                         continue;
3970
3971                 // Don't send if it's the same one
3972                 if(client->peer_id == ignore_id)
3973                         continue;
3974                 
3975                 if(far_players)
3976                 {
3977                         // Get player
3978                         Player *player = m_env.getPlayer(client->peer_id);
3979                         if(player)
3980                         {
3981                                 // If player is far away, only set modified blocks not sent
3982                                 v3f player_pos = player->getPosition();
3983                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3984                                 {
3985                                         far_players->push_back(client->peer_id);
3986                                         continue;
3987                                 }
3988                         }
3989                 }
3990
3991                 // Send as reliable
3992                 m_con.Send(client->peer_id, 0, reply, true);
3993         }
3994 }
3995
3996 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3997                 core::list<u16> *far_players, float far_d_nodes)
3998 {
3999         float maxd = far_d_nodes*BS;
4000         v3f p_f = intToFloat(p, BS);
4001
4002         for(core::map<u16, RemoteClient*>::Iterator
4003                 i = m_clients.getIterator();
4004                 i.atEnd() == false; i++)
4005         {
4006                 // Get client and check that it is valid
4007                 RemoteClient *client = i.getNode()->getValue();
4008                 assert(client->peer_id == i.getNode()->getKey());
4009                 if(client->serialization_version == SER_FMT_VER_INVALID)
4010                         continue;
4011
4012                 // Don't send if it's the same one
4013                 if(client->peer_id == ignore_id)
4014                         continue;
4015
4016                 if(far_players)
4017                 {
4018                         // Get player
4019                         Player *player = m_env.getPlayer(client->peer_id);
4020                         if(player)
4021                         {
4022                                 // If player is far away, only set modified blocks not sent
4023                                 v3f player_pos = player->getPosition();
4024                                 if(player_pos.getDistanceFrom(p_f) > maxd)
4025                                 {
4026                                         far_players->push_back(client->peer_id);
4027                                         continue;
4028                                 }
4029                         }
4030                 }
4031
4032                 // Create packet
4033                 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4034                 SharedBuffer<u8> reply(replysize);
4035                 writeU16(&reply[0], TOCLIENT_ADDNODE);
4036                 writeS16(&reply[2], p.X);
4037                 writeS16(&reply[4], p.Y);
4038                 writeS16(&reply[6], p.Z);
4039                 n.serialize(&reply[8], client->serialization_version);
4040
4041                 // Send as reliable
4042                 m_con.Send(client->peer_id, 0, reply, true);
4043         }
4044 }
4045
4046 void Server::setBlockNotSent(v3s16 p)
4047 {
4048         for(core::map<u16, RemoteClient*>::Iterator
4049                 i = m_clients.getIterator();
4050                 i.atEnd()==false; i++)
4051         {
4052                 RemoteClient *client = i.getNode()->getValue();
4053                 client->SetBlockNotSent(p);
4054         }
4055 }
4056
4057 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4058 {
4059         DSTACK(__FUNCTION_NAME);
4060
4061         v3s16 p = block->getPos();
4062         
4063 #if 0
4064         // Analyze it a bit
4065         bool completely_air = true;
4066         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4067         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4068         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4069         {
4070                 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4071                 {
4072                         completely_air = false;
4073                         x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4074                 }
4075         }
4076
4077         // Print result
4078         dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4079         if(completely_air)
4080                 dstream<<"[completely air] ";
4081         dstream<<std::endl;
4082 #endif
4083
4084         /*
4085                 Create a packet with the block in the right format
4086         */
4087         
4088         std::ostringstream os(std::ios_base::binary);
4089         block->serialize(os, ver);
4090         std::string s = os.str();
4091         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4092
4093         u32 replysize = 8 + blockdata.getSize();
4094         SharedBuffer<u8> reply(replysize);
4095         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4096         writeS16(&reply[2], p.X);
4097         writeS16(&reply[4], p.Y);
4098         writeS16(&reply[6], p.Z);
4099         memcpy(&reply[8], *blockdata, blockdata.getSize());
4100
4101         /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4102                         <<":  \tpacket size: "<<replysize<<std::endl;*/
4103         
4104         /*
4105                 Send packet
4106         */
4107         m_con.Send(peer_id, 1, reply, true);
4108 }
4109
4110 void Server::SendBlocks(float dtime)
4111 {
4112         DSTACK(__FUNCTION_NAME);
4113
4114         JMutexAutoLock envlock(m_env_mutex);
4115         JMutexAutoLock conlock(m_con_mutex);
4116
4117         //TimeTaker timer("Server::SendBlocks");
4118
4119         core::array<PrioritySortedBlockTransfer> queue;
4120
4121         s32 total_sending = 0;
4122         
4123         {
4124                 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4125
4126                 for(core::map<u16, RemoteClient*>::Iterator
4127                         i = m_clients.getIterator();
4128                         i.atEnd() == false; i++)
4129                 {
4130                         RemoteClient *client = i.getNode()->getValue();
4131                         assert(client->peer_id == i.getNode()->getKey());
4132
4133                         total_sending += client->SendingCount();
4134                         
4135                         if(client->serialization_version == SER_FMT_VER_INVALID)
4136                                 continue;
4137                         
4138                         client->GetNextBlocks(this, dtime, queue);
4139                 }
4140         }
4141
4142         // Sort.
4143         // Lowest priority number comes first.
4144         // Lowest is most important.
4145         queue.sort();
4146
4147         for(u32 i=0; i<queue.size(); i++)
4148         {
4149                 //TODO: Calculate limit dynamically
4150                 if(total_sending >= g_settings->getS32
4151                                 ("max_simultaneous_block_sends_server_total"))
4152                         break;
4153                 
4154                 PrioritySortedBlockTransfer q = queue[i];
4155
4156                 MapBlock *block = NULL;
4157                 try
4158                 {
4159                         block = m_env.getMap().getBlockNoCreate(q.pos);
4160                 }
4161                 catch(InvalidPositionException &e)
4162                 {
4163                         continue;
4164                 }
4165
4166                 RemoteClient *client = getClient(q.peer_id);
4167
4168                 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4169
4170                 client->SentBlock(q.pos);
4171
4172                 total_sending++;
4173         }
4174 }
4175
4176 /*
4177         Something random
4178 */
4179
4180 void Server::UpdateCrafting(u16 peer_id)
4181 {
4182         DSTACK(__FUNCTION_NAME);
4183         
4184         Player* player = m_env.getPlayer(peer_id);
4185         assert(player);
4186
4187         /*
4188                 Calculate crafting stuff
4189         */
4190         if(g_settings->getBool("creative_mode") == false)
4191         {
4192                 InventoryList *clist = player->inventory.getList("craft");
4193                 InventoryList *rlist = player->inventory.getList("craftresult");
4194
4195                 if(rlist && rlist->getUsedSlots() == 0)
4196                         player->craftresult_is_preview = true;
4197
4198                 if(rlist && player->craftresult_is_preview)
4199                 {
4200                         rlist->clearItems();
4201                 }
4202                 if(clist && rlist && player->craftresult_is_preview)
4203                 {
4204                         InventoryItem *items[9];
4205                         for(u16 i=0; i<9; i++)
4206                         {
4207                                 items[i] = clist->getItem(i);
4208                         }
4209                         
4210                         // Get result of crafting grid
4211                         InventoryItem *result = craft_get_result(items);
4212                         if(result)
4213                                 rlist->addItem(result);
4214                 }
4215         
4216         } // if creative_mode == false
4217 }
4218
4219 RemoteClient* Server::getClient(u16 peer_id)
4220 {
4221         DSTACK(__FUNCTION_NAME);
4222         //JMutexAutoLock lock(m_con_mutex);
4223         core::map<u16, RemoteClient*>::Node *n;
4224         n = m_clients.find(peer_id);
4225         // A client should exist for all peers
4226         assert(n != NULL);
4227         return n->getValue();
4228 }
4229
4230 std::wstring Server::getStatusString()
4231 {
4232         std::wostringstream os(std::ios_base::binary);
4233         os<<L"# Server: ";
4234         // Version
4235         os<<L"version="<<narrow_to_wide(VERSION_STRING);
4236         // Uptime
4237         os<<L", uptime="<<m_uptime.get();
4238         // Information about clients
4239         os<<L", clients={";
4240         for(core::map<u16, RemoteClient*>::Iterator
4241                 i = m_clients.getIterator();
4242                 i.atEnd() == false; i++)
4243         {
4244                 // Get client and check that it is valid
4245                 RemoteClient *client = i.getNode()->getValue();
4246                 assert(client->peer_id == i.getNode()->getKey());
4247                 if(client->serialization_version == SER_FMT_VER_INVALID)
4248                         continue;
4249                 // Get player
4250                 Player *player = m_env.getPlayer(client->peer_id);
4251                 // Get name of player
4252                 std::wstring name = L"unknown";
4253                 if(player != NULL)
4254                         name = narrow_to_wide(player->getName());
4255                 // Add name to information string
4256                 os<<name<<L",";
4257         }
4258         os<<L"}";
4259         if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
4260                 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4261         if(g_settings->get("motd") != "")
4262                 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4263         return os.str();
4264 }
4265
4266 // Saves g_settings to configpath given at initialization
4267 void Server::saveConfig()
4268 {
4269         if(m_configpath != "")
4270                 g_settings->updateConfigFile(m_configpath.c_str());
4271 }
4272
4273 v3f findSpawnPos(ServerMap &map)
4274 {
4275         //return v3f(50,50,50)*BS;
4276
4277         v2s16 nodepos;
4278         s16 groundheight = 0;
4279         
4280 #if 0
4281         nodepos = v2s16(0,0);
4282         groundheight = 20;
4283 #endif
4284
4285 #if 1
4286         // Try to find a good place a few times
4287         for(s32 i=0; i<1000; i++)
4288         {
4289                 s32 range = 1 + i;
4290                 // We're going to try to throw the player to this position
4291                 nodepos = v2s16(-range + (myrand()%(range*2)),
4292                                 -range + (myrand()%(range*2)));
4293                 v2s16 sectorpos = getNodeSectorPos(nodepos);
4294                 // Get sector (NOTE: Don't get because it's slow)
4295                 //m_env.getMap().emergeSector(sectorpos);
4296                 // Get ground height at point (fallbacks to heightmap function)
4297                 groundheight = map.findGroundLevel(nodepos);
4298                 // Don't go underwater
4299                 if(groundheight < WATER_LEVEL)
4300                 {
4301                         //dstream<<"-> Underwater"<<std::endl;
4302                         continue;
4303                 }
4304                 // Don't go to high places
4305                 if(groundheight > WATER_LEVEL + 4)
4306                 {
4307                         //dstream<<"-> Underwater"<<std::endl;
4308                         continue;
4309                 }
4310
4311                 // Found a good place
4312                 //dstream<<"Searched through "<<i<<" places."<<std::endl;
4313                 break;
4314         }
4315 #endif
4316         
4317         // If no suitable place was not found, go above water at least.
4318         if(groundheight < WATER_LEVEL)
4319                 groundheight = WATER_LEVEL;
4320
4321         return intToFloat(v3s16(
4322                         nodepos.X,
4323                         groundheight + 3,
4324                         nodepos.Y
4325                         ), BS);
4326 }
4327
4328 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4329 {
4330         /*
4331                 Try to get an existing player
4332         */
4333         Player *player = m_env.getPlayer(name);
4334         if(player != NULL)
4335         {
4336                 // If player is already connected, cancel
4337                 if(player->peer_id != 0)
4338                 {
4339                         dstream<<"emergePlayer(): Player already connected"<<std::endl;
4340                         return NULL;
4341                 }
4342
4343                 // Got one.
4344                 player->peer_id = peer_id;
4345                 
4346                 // Reset inventory to creative if in creative mode
4347                 if(g_settings->getBool("creative_mode"))
4348                 {
4349                         // Warning: double code below
4350                         // Backup actual inventory
4351                         player->inventory_backup = new Inventory();
4352                         *(player->inventory_backup) = player->inventory;
4353                         // Set creative inventory
4354                         craft_set_creative_inventory(player);
4355                 }
4356
4357                 return player;
4358         }
4359
4360         /*
4361                 If player with the wanted peer_id already exists, cancel.
4362         */
4363         if(m_env.getPlayer(peer_id) != NULL)
4364         {
4365                 dstream<<"emergePlayer(): Player with wrong name but same"
4366                                 " peer_id already exists"<<std::endl;
4367                 return NULL;
4368         }
4369         
4370         /*
4371                 Create a new player
4372         */
4373         {
4374                 player = new ServerRemotePlayer();
4375                 //player->peer_id = c.peer_id;
4376                 //player->peer_id = PEER_ID_INEXISTENT;
4377                 player->peer_id = peer_id;
4378                 player->updateName(name);
4379                 m_authmanager.add(name);
4380                 m_authmanager.setPassword(name, password);
4381                 m_authmanager.setPrivs(name,
4382                                 stringToPrivs(g_settings->get("default_privs")));
4383
4384                 /*
4385                         Set player position
4386                 */
4387                 
4388                 dstream<<"Server: Finding spawn place for player \""
4389                                 <<player->getName()<<"\""<<std::endl;
4390
4391                 v3f pos = findSpawnPos(m_env.getServerMap());
4392
4393                 player->setPosition(pos);
4394
4395                 /*
4396                         Add player to environment
4397                 */
4398
4399                 m_env.addPlayer(player);
4400
4401                 /*
4402                         Add stuff to inventory
4403                 */
4404                 
4405                 if(g_settings->getBool("creative_mode"))
4406                 {
4407                         // Warning: double code above
4408                         // Backup actual inventory
4409                         player->inventory_backup = new Inventory();
4410                         *(player->inventory_backup) = player->inventory;
4411                         // Set creative inventory
4412                         craft_set_creative_inventory(player);
4413                 }
4414                 else if(g_settings->getBool("give_initial_stuff"))
4415                 {
4416                         craft_give_initial_stuff(player);
4417                 }
4418
4419                 return player;
4420                 
4421         } // create new player
4422 }
4423
4424 void Server::handlePeerChange(PeerChange &c)
4425 {
4426         JMutexAutoLock envlock(m_env_mutex);
4427         JMutexAutoLock conlock(m_con_mutex);
4428         
4429         if(c.type == PEER_ADDED)
4430         {
4431                 /*
4432                         Add
4433                 */
4434
4435                 // Error check
4436                 core::map<u16, RemoteClient*>::Node *n;
4437                 n = m_clients.find(c.peer_id);
4438                 // The client shouldn't already exist
4439                 assert(n == NULL);
4440
4441                 // Create client
4442                 RemoteClient *client = new RemoteClient();
4443                 client->peer_id = c.peer_id;
4444                 m_clients.insert(client->peer_id, client);
4445
4446         } // PEER_ADDED
4447         else if(c.type == PEER_REMOVED)
4448         {
4449                 /*
4450                         Delete
4451                 */
4452
4453                 // Error check
4454                 core::map<u16, RemoteClient*>::Node *n;
4455                 n = m_clients.find(c.peer_id);
4456                 // The client should exist
4457                 assert(n != NULL);
4458                 
4459                 /*
4460                         Mark objects to be not known by the client
4461                 */
4462                 RemoteClient *client = n->getValue();
4463                 // Handle objects
4464                 for(core::map<u16, bool>::Iterator
4465                                 i = client->m_known_objects.getIterator();
4466                                 i.atEnd()==false; i++)
4467                 {
4468                         // Get object
4469                         u16 id = i.getNode()->getKey();
4470                         ServerActiveObject* obj = m_env.getActiveObject(id);
4471                         
4472                         if(obj && obj->m_known_by_count > 0)
4473                                 obj->m_known_by_count--;
4474                 }
4475
4476                 // Collect information about leaving in chat
4477                 std::wstring message;
4478                 {
4479                         Player *player = m_env.getPlayer(c.peer_id);
4480                         if(player != NULL)
4481                         {
4482                                 std::wstring name = narrow_to_wide(player->getName());
4483                                 message += L"*** ";
4484                                 message += name;
4485                                 message += L" left game";
4486                                 if(c.timeout)
4487                                         message += L" (timed out)";
4488                         }
4489                 }
4490
4491                 /*// Delete player
4492                 {
4493                         m_env.removePlayer(c.peer_id);
4494                 }*/
4495
4496                 // Set player client disconnected
4497                 {
4498                         Player *player = m_env.getPlayer(c.peer_id);
4499                         if(player != NULL)
4500                                 player->peer_id = 0;
4501                 }
4502                 
4503                 // Delete client
4504                 delete m_clients[c.peer_id];
4505                 m_clients.remove(c.peer_id);
4506
4507                 // Send player info to all remaining clients
4508                 SendPlayerInfos();
4509                 
4510                 // Send leave chat message to all remaining clients
4511                 BroadcastChatMessage(message);
4512                 
4513         } // PEER_REMOVED
4514         else
4515         {
4516                 assert(0);
4517         }
4518 }
4519
4520 void Server::handlePeerChanges()
4521 {
4522         while(m_peer_change_queue.size() > 0)
4523         {
4524                 PeerChange c = m_peer_change_queue.pop_front();
4525
4526                 dout_server<<"Server: Handling peer change: "
4527                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4528                                 <<std::endl;
4529
4530                 handlePeerChange(c);
4531         }
4532 }
4533
4534 u64 Server::getPlayerPrivs(Player *player)
4535 {
4536         if(player==NULL)
4537                 return 0;
4538         std::string playername = player->getName();
4539         // Local player gets all privileges regardless of
4540         // what's set on their account.
4541         if(g_settings->get("name") == playername)
4542         {
4543                 return PRIV_ALL;
4544         }
4545         else
4546         {
4547                 return getPlayerAuthPrivs(playername);
4548         }
4549 }
4550
4551 void dedicated_server_loop(Server &server, bool &kill)
4552 {
4553         DSTACK(__FUNCTION_NAME);
4554         
4555         dstream<<DTIME<<std::endl;
4556         dstream<<"========================"<<std::endl;
4557         dstream<<"Running dedicated server"<<std::endl;
4558         dstream<<"========================"<<std::endl;
4559         dstream<<std::endl;
4560
4561         IntervalLimiter m_profiler_interval;
4562
4563         for(;;)
4564         {
4565                 // This is kind of a hack but can be done like this
4566                 // because server.step() is very light
4567                 {
4568                         ScopeProfiler sp(g_profiler, "dedicated server sleep");
4569                         sleep_ms(30);
4570                 }
4571                 server.step(0.030);
4572
4573                 if(server.getShutdownRequested() || kill)
4574                 {
4575                         dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4576                         break;
4577                 }
4578
4579                 /*
4580                         Profiler
4581                 */
4582                 float profiler_print_interval =
4583                                 g_settings->getFloat("profiler_print_interval");
4584                 if(profiler_print_interval != 0)
4585                 {
4586                         if(m_profiler_interval.step(0.030, profiler_print_interval))
4587                         {
4588                                 dstream<<"Profiler:"<<std::endl;
4589                                 g_profiler->print(dstream);
4590                                 g_profiler->clear();
4591                         }
4592                 }
4593                 
4594                 /*
4595                         Player info
4596                 */
4597                 static int counter = 0;
4598                 counter--;
4599                 if(counter <= 0)
4600                 {
4601                         counter = 10;
4602
4603                         core::list<PlayerInfo> list = server.getPlayerInfo();
4604                         core::list<PlayerInfo>::Iterator i;
4605                         static u32 sum_old = 0;
4606                         u32 sum = PIChecksum(list);
4607                         if(sum != sum_old)
4608                         {
4609                                 dstream<<DTIME<<"Player info:"<<std::endl;
4610                                 for(i=list.begin(); i!=list.end(); i++)
4611                                 {
4612                                         i->PrintLine(&dstream);
4613                                 }
4614                         }
4615                         sum_old = sum;
4616                 }
4617         }
4618 }
4619
4620