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