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