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