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