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