5646c0ac9c9dffdccff84b15f7e5ee00d83ce738
[oweals/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                 std::string checkpwd;
2175                 if(m_authmanager.exists(playername))
2176                 {
2177                         checkpwd = m_authmanager.getPassword(playername);
2178                 }
2179                 else
2180                 {
2181                         checkpwd = g_settings->get("default_password");
2182                 }
2183                 
2184                 /*infostream<<"Server: Client gave password '"<<password
2185                                 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2186                 
2187                 if(password != checkpwd && m_authmanager.exists(playername))
2188                 {
2189                         infostream<<"Server: peer_id="<<peer_id
2190                                         <<": supplied invalid password for "
2191                                         <<playername<<std::endl;
2192                         SendAccessDenied(m_con, peer_id, L"Invalid password");
2193                         return;
2194                 }
2195                 
2196                 // Add player to auth manager
2197                 if(m_authmanager.exists(playername) == false)
2198                 {
2199                         infostream<<"Server: adding player "<<playername
2200                                         <<" to auth manager"<<std::endl;
2201                         m_authmanager.add(playername);
2202                         m_authmanager.setPassword(playername, checkpwd);
2203                         m_authmanager.setPrivs(playername,
2204                                         stringToPrivs(g_settings->get("default_privs")));
2205                         m_authmanager.save();
2206                 }
2207                 
2208                 // Enforce user limit.
2209                 // Don't enforce for users that have some admin right
2210                 if(m_clients.size() >= g_settings->getU16("max_users") &&
2211                                 (m_authmanager.getPrivs(playername)
2212                                         & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS)) == 0 &&
2213                                 playername != g_settings->get("name"))
2214                 {
2215                         SendAccessDenied(m_con, peer_id, L"Too many users.");
2216                         return;
2217                 }
2218
2219                 // Get player
2220                 Player *player = emergePlayer(playername, password, peer_id);
2221
2222                 // If failed, cancel
2223                 if(player == NULL)
2224                 {
2225                         infostream<<"Server: peer_id="<<peer_id
2226                                         <<": failed to emerge player"<<std::endl;
2227                         return;
2228                 }
2229
2230                 /*
2231                         Answer with a TOCLIENT_INIT
2232                 */
2233                 {
2234                         SharedBuffer<u8> reply(2+1+6+8);
2235                         writeU16(&reply[0], TOCLIENT_INIT);
2236                         writeU8(&reply[2], deployed);
2237                         writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2238                         writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2239                         
2240                         // Send as reliable
2241                         m_con.Send(peer_id, 0, reply, true);
2242                 }
2243
2244                 /*
2245                         Send complete position information
2246                 */
2247                 SendMovePlayer(player);
2248
2249                 return;
2250         }
2251
2252         if(command == TOSERVER_INIT2)
2253         {
2254                 infostream<<"Server: Got TOSERVER_INIT2 from "
2255                                 <<peer_id<<std::endl;
2256
2257
2258                 getClient(peer_id)->serialization_version
2259                                 = getClient(peer_id)->pending_serialization_version;
2260
2261                 /*
2262                         Send some initialization data
2263                 */
2264
2265                 // Send tool definitions
2266                 SendToolDef(m_con, peer_id, m_toolmgr);
2267                 
2268                 // Send node definitions
2269                 SendNodeDef(m_con, peer_id, m_nodedef);
2270                 
2271                 // Send CraftItem definitions
2272                 SendCraftItemDef(m_con, peer_id, m_craftitemdef);
2273                 
2274                 // Send textures
2275                 SendTextures(peer_id);
2276                 
2277                 // Send player info to all players
2278                 SendPlayerInfos();
2279
2280                 // Send inventory to player
2281                 UpdateCrafting(peer_id);
2282                 SendInventory(peer_id);
2283
2284                 // Send player items to all players
2285                 SendPlayerItems();
2286
2287                 Player *player = m_env->getPlayer(peer_id);
2288
2289                 // Send HP
2290                 SendPlayerHP(player);
2291                 
2292                 // Send time of day
2293                 {
2294                         SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2295                                         m_env->getTimeOfDay());
2296                         m_con.Send(peer_id, 0, data, true);
2297                 }
2298                 
2299                 // Send information about server to player in chat
2300                 SendChatMessage(peer_id, getStatusString());
2301                 
2302                 // Send information about joining in chat
2303                 {
2304                         std::wstring name = L"unknown";
2305                         Player *player = m_env->getPlayer(peer_id);
2306                         if(player != NULL)
2307                                 name = narrow_to_wide(player->getName());
2308                         
2309                         std::wstring message;
2310                         message += L"*** ";
2311                         message += name;
2312                         message += L" joined game";
2313                         BroadcastChatMessage(message);
2314                 }
2315                 
2316                 // Warnings about protocol version can be issued here
2317                 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2318                 {
2319                         SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2320                 }
2321
2322                 /*
2323                         Check HP, respawn if necessary
2324                 */
2325                 HandlePlayerHP(player, 0);
2326
2327                 /*
2328                         Print out action
2329                 */
2330                 {
2331                         std::ostringstream os(std::ios_base::binary);
2332                         for(core::map<u16, RemoteClient*>::Iterator
2333                                 i = m_clients.getIterator();
2334                                 i.atEnd() == false; i++)
2335                         {
2336                                 RemoteClient *client = i.getNode()->getValue();
2337                                 assert(client->peer_id == i.getNode()->getKey());
2338                                 if(client->serialization_version == SER_FMT_VER_INVALID)
2339                                         continue;
2340                                 // Get player
2341                                 Player *player = m_env->getPlayer(client->peer_id);
2342                                 if(!player)
2343                                         continue;
2344                                 // Get name of player
2345                                 os<<player->getName()<<" ";
2346                         }
2347
2348                         actionstream<<player->getName()<<" joins game. List of players: "
2349                                         <<os.str()<<std::endl;
2350                 }
2351
2352                 return;
2353         }
2354
2355         if(peer_ser_ver == SER_FMT_VER_INVALID)
2356         {
2357                 infostream<<"Server::ProcessData(): Cancelling: Peer"
2358                                 " serialization format invalid or not initialized."
2359                                 " Skipping incoming command="<<command<<std::endl;
2360                 return;
2361         }
2362         
2363         Player *player = m_env->getPlayer(peer_id);
2364         ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
2365
2366         if(player == NULL){
2367                 infostream<<"Server::ProcessData(): Cancelling: "
2368                                 "No player for peer_id="<<peer_id
2369                                 <<std::endl;
2370                 return;
2371         }
2372         if(command == TOSERVER_PLAYERPOS)
2373         {
2374                 if(datasize < 2+12+12+4+4)
2375                         return;
2376         
2377                 u32 start = 0;
2378                 v3s32 ps = readV3S32(&data[start+2]);
2379                 v3s32 ss = readV3S32(&data[start+2+12]);
2380                 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2381                 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2382                 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2383                 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2384                 pitch = wrapDegrees(pitch);
2385                 yaw = wrapDegrees(yaw);
2386
2387                 player->setPosition(position);
2388                 player->setSpeed(speed);
2389                 player->setPitch(pitch);
2390                 player->setYaw(yaw);
2391                 
2392                 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2393                                 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2394                                 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2395         }
2396         else if(command == TOSERVER_GOTBLOCKS)
2397         {
2398                 if(datasize < 2+1)
2399                         return;
2400                 
2401                 /*
2402                         [0] u16 command
2403                         [2] u8 count
2404                         [3] v3s16 pos_0
2405                         [3+6] v3s16 pos_1
2406                         ...
2407                 */
2408
2409                 u16 count = data[2];
2410                 for(u16 i=0; i<count; i++)
2411                 {
2412                         if((s16)datasize < 2+1+(i+1)*6)
2413                                 throw con::InvalidIncomingDataException
2414                                         ("GOTBLOCKS length is too short");
2415                         v3s16 p = readV3S16(&data[2+1+i*6]);
2416                         /*infostream<<"Server: GOTBLOCKS ("
2417                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2418                         RemoteClient *client = getClient(peer_id);
2419                         client->GotBlock(p);
2420                 }
2421         }
2422         else if(command == TOSERVER_DELETEDBLOCKS)
2423         {
2424                 if(datasize < 2+1)
2425                         return;
2426                 
2427                 /*
2428                         [0] u16 command
2429                         [2] u8 count
2430                         [3] v3s16 pos_0
2431                         [3+6] v3s16 pos_1
2432                         ...
2433                 */
2434
2435                 u16 count = data[2];
2436                 for(u16 i=0; i<count; i++)
2437                 {
2438                         if((s16)datasize < 2+1+(i+1)*6)
2439                                 throw con::InvalidIncomingDataException
2440                                         ("DELETEDBLOCKS length is too short");
2441                         v3s16 p = readV3S16(&data[2+1+i*6]);
2442                         /*infostream<<"Server: DELETEDBLOCKS ("
2443                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2444                         RemoteClient *client = getClient(peer_id);
2445                         client->SetBlockNotSent(p);
2446                 }
2447         }
2448         else if(command == TOSERVER_CLICK_OBJECT)
2449         {
2450                 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2451                 return;
2452         }
2453         else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2454         {
2455                 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2456                 return;
2457         }
2458         else if(command == TOSERVER_GROUND_ACTION)
2459         {
2460                 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2461                 return;
2462
2463         }
2464         else if(command == TOSERVER_RELEASE)
2465         {
2466                 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2467                 return;
2468         }
2469         else if(command == TOSERVER_SIGNTEXT)
2470         {
2471                 infostream<<"Server: SIGNTEXT not supported anymore"
2472                                 <<std::endl;
2473                 return;
2474         }
2475         else if(command == TOSERVER_SIGNNODETEXT)
2476         {
2477                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2478                         return;
2479                 /*
2480                         u16 command
2481                         v3s16 p
2482                         u16 textlen
2483                         textdata
2484                 */
2485                 std::string datastring((char*)&data[2], datasize-2);
2486                 std::istringstream is(datastring, std::ios_base::binary);
2487                 u8 buf[6];
2488                 // Read stuff
2489                 is.read((char*)buf, 6);
2490                 v3s16 p = readV3S16(buf);
2491                 is.read((char*)buf, 2);
2492                 u16 textlen = readU16(buf);
2493                 std::string text;
2494                 for(u16 i=0; i<textlen; i++)
2495                 {
2496                         is.read((char*)buf, 1);
2497                         text += (char)buf[0];
2498                 }
2499
2500                 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2501                 if(!meta)
2502                         return;
2503
2504                 meta->setText(text);
2505                 
2506                 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign"
2507                                 <<" at "<<PP(p)<<std::endl;
2508                                 
2509                 v3s16 blockpos = getNodeBlockPos(p);
2510                 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2511                 if(block)
2512                 {
2513                         block->raiseModified(MOD_STATE_WRITE_NEEDED,
2514                                         "sign node text");
2515                 }
2516
2517                 setBlockNotSent(blockpos);
2518         }
2519         else if(command == TOSERVER_INVENTORY_ACTION)
2520         {
2521                 /*// Ignore inventory changes if in creative mode
2522                 if(g_settings->getBool("creative_mode") == true)
2523                 {
2524                         infostream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
2525                                         <<std::endl;
2526                         return;
2527                 }*/
2528                 // Strip command and create a stream
2529                 std::string datastring((char*)&data[2], datasize-2);
2530                 infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2531                 std::istringstream is(datastring, std::ios_base::binary);
2532                 // Create an action
2533                 InventoryAction *a = InventoryAction::deSerialize(is);
2534                 if(a == NULL)
2535                 {
2536                         infostream<<"TOSERVER_INVENTORY_ACTION: "
2537                                         <<"InventoryAction::deSerialize() returned NULL"
2538                                         <<std::endl;
2539                         return;
2540                 }
2541                 // Create context
2542                 InventoryContext c;
2543                 c.current_player = player;
2544
2545                 /*
2546                         Handle restrictions and special cases of the move action
2547                 */
2548                 if(a->getType() == IACTION_MOVE
2549                                 && g_settings->getBool("creative_mode") == false)
2550                 {
2551                         InventoryList *rlist = player->inventory.getList("craftresult");
2552                         assert(rlist);
2553                         InventoryList *clist = player->inventory.getList("craft");
2554                         assert(clist);
2555                         InventoryList *mlist = player->inventory.getList("main");
2556                         assert(mlist);
2557
2558                         IMoveAction *ma = (IMoveAction*)a;
2559
2560                         /*
2561                                 Disable moving items into craftresult from elsewhere
2562                         */
2563                         if(ma->to_inv == "current_player"
2564                                         && ma->to_list == "craftresult"
2565                                         && (ma->from_inv != "current_player"
2566                                         || ma->from_list != "craftresult"))
2567                         {
2568                                 infostream<<"Ignoring IMoveAction from "
2569                                                 <<ma->from_inv<<":"<<ma->from_list
2570                                                 <<" to "<<ma->to_inv<<":"<<ma->to_list
2571                                                 <<" because dst is craftresult"
2572                                                 <<" and src isn't craftresult"<<std::endl;
2573                                 delete a;
2574                                 return;
2575                         }
2576
2577                         /*
2578                                 Handle crafting (source is craftresult, which is preview)
2579                         */
2580                         if(ma->from_inv == "current_player"
2581                                         && ma->from_list == "craftresult"
2582                                         && player->craftresult_is_preview)
2583                         {
2584                                 /*
2585                                         If the craftresult is placed on itself, crafting takes
2586                                         place and result is moved into main list
2587                                 */
2588                                 if(ma->to_inv == "current_player"
2589                                                 && ma->to_list == "craftresult")
2590                                 {
2591                                         // Except if main list doesn't have free slots
2592                                         if(mlist->getFreeSlots() == 0){
2593                                                 infostream<<"Cannot craft: Main list doesn't have"
2594                                                                 <<" free slots"<<std::endl;
2595                                                 delete a;
2596                                                 return;
2597                                         }
2598                                         
2599                                         player->craftresult_is_preview = false;
2600                                         clist->decrementMaterials(1);
2601
2602                                         InventoryItem *item1 = rlist->changeItem(0, NULL);
2603                                         mlist->addItem(item1);
2604
2605                                         srp->m_inventory_not_sent = true;
2606
2607                                         delete a;
2608                                         return;
2609                                 }
2610                                 /*
2611                                         Disable action if there are no free slots in
2612                                         destination
2613                                         
2614                                         If the item is placed on an item that is not of the
2615                                         same kind, the existing item will be first moved to
2616                                         craftresult and immediately moved to the free slot.
2617                                 */
2618                                 do{
2619                                         Inventory *inv_to = getInventory(&c, ma->to_inv);
2620                                         if(!inv_to) break;
2621                                         InventoryList *list_to = inv_to->getList(ma->to_list);
2622                                         if(!list_to) break;
2623                                         if(list_to->getFreeSlots() == 0){
2624                                                 infostream<<"Cannot craft: Destination doesn't have"
2625                                                                 <<" free slots"<<std::endl;
2626                                                 delete a;
2627                                                 return;
2628                                         }
2629                                 }while(0); // Allow break
2630
2631                                 /*
2632                                         Ok, craft normally.
2633                                 */
2634                                 player->craftresult_is_preview = false;
2635                                 clist->decrementMaterials(1);
2636                                 
2637                                 /* Print out action */
2638                                 InventoryItem *item = rlist->getItem(0);
2639                                 std::string itemstring = "NULL";
2640                                 if(item)
2641                                         itemstring = item->getItemString();
2642                                 actionstream<<player->getName()<<" crafts "
2643                                                 <<itemstring<<std::endl;
2644
2645                                 // Do the action
2646                                 a->apply(&c, this, m_env);
2647                                 
2648                                 delete a;
2649                                 return;
2650                         }
2651
2652                         /*
2653                                 Non-crafting move
2654                         */
2655                         
2656                         // Disallow moving items in elsewhere than player's inventory
2657                         // if not allowed to build
2658                         if((getPlayerPrivs(player) & PRIV_BUILD) == 0
2659                                         && (ma->from_inv != "current_player"
2660                                         || ma->to_inv != "current_player"))
2661                         {
2662                                 infostream<<"Cannot move outside of player's inventory: "
2663                                                 <<"No build privilege"<<std::endl;
2664                                 delete a;
2665                                 return;
2666                         }
2667
2668                         // If player is not an admin, check for ownership of src
2669                         if(ma->from_inv != "current_player"
2670                                         && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
2671                         {
2672                                 Strfnd fn(ma->from_inv);
2673                                 std::string id0 = fn.next(":");
2674                                 if(id0 == "nodemeta")
2675                                 {
2676                                         v3s16 p;
2677                                         p.X = stoi(fn.next(","));
2678                                         p.Y = stoi(fn.next(","));
2679                                         p.Z = stoi(fn.next(","));
2680                                         NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2681                                         if(meta->getOwner() != "" &&
2682                                                         meta->getOwner() != player->getName())
2683                                         {
2684                                                 infostream<<"Cannot move item: "
2685                                                                 "not owner of metadata"
2686                                                                 <<std::endl;
2687                                                 delete a;
2688                                                 return;
2689                                         }
2690                                 }
2691                         }
2692                         // If player is not an admin, check for ownership of dst
2693                         if(ma->to_inv != "current_player"
2694                                         && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
2695                         {
2696                                 Strfnd fn(ma->to_inv);
2697                                 std::string id0 = fn.next(":");
2698                                 if(id0 == "nodemeta")
2699                                 {
2700                                         v3s16 p;
2701                                         p.X = stoi(fn.next(","));
2702                                         p.Y = stoi(fn.next(","));
2703                                         p.Z = stoi(fn.next(","));
2704                                         NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2705                                         if(meta->getOwner() != "" &&
2706                                                         meta->getOwner() != player->getName())
2707                                         {
2708                                                 infostream<<"Cannot move item: "
2709                                                                 "not owner of metadata"
2710                                                                 <<std::endl;
2711                                                 delete a;
2712                                                 return;
2713                                         }
2714                                 }
2715                         }
2716                 }
2717                 /*
2718                         Handle restrictions and special cases of the drop action
2719                 */
2720                 else if(a->getType() == IACTION_DROP)
2721                 {
2722                         IDropAction *da = (IDropAction*)a;
2723                         // Disallow dropping items if not allowed to build
2724                         if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2725                         {
2726                                 delete a;
2727                                 return;
2728                         }
2729                         // If player is not an admin, check for ownership
2730                         else if (da->from_inv != "current_player"
2731                                         && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
2732                         {
2733                                 Strfnd fn(da->from_inv);
2734                                 std::string id0 = fn.next(":");
2735                                 if(id0 == "nodemeta")
2736                                 {
2737                                         v3s16 p;
2738                                         p.X = stoi(fn.next(","));
2739                                         p.Y = stoi(fn.next(","));
2740                                         p.Z = stoi(fn.next(","));
2741                                         NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2742                                         if(meta->getOwner() != "" &&
2743                                                         meta->getOwner() != player->getName())
2744                                         {
2745                                                 infostream<<"Cannot move item: "
2746                                                                 "not owner of metadata"
2747                                                                 <<std::endl;
2748                                                 delete a;
2749                                                 return;
2750                                         }
2751                                 }
2752                         }
2753                 }
2754                 
2755                 // Do the action
2756                 a->apply(&c, this, m_env);
2757                 // Eat the action
2758                 delete a;
2759         }
2760         else if(command == TOSERVER_CHAT_MESSAGE)
2761         {
2762                 /*
2763                         u16 command
2764                         u16 length
2765                         wstring message
2766                 */
2767                 u8 buf[6];
2768                 std::string datastring((char*)&data[2], datasize-2);
2769                 std::istringstream is(datastring, std::ios_base::binary);
2770                 
2771                 // Read stuff
2772                 is.read((char*)buf, 2);
2773                 u16 len = readU16(buf);
2774                 
2775                 std::wstring message;
2776                 for(u16 i=0; i<len; i++)
2777                 {
2778                         is.read((char*)buf, 2);
2779                         message += (wchar_t)readU16(buf);
2780                 }
2781
2782                 // Get player name of this client
2783                 std::wstring name = narrow_to_wide(player->getName());
2784                 
2785                 // Run script hook
2786                 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2787                                 wide_to_narrow(message));
2788                 // If script ate the message, don't proceed
2789                 if(ate)
2790                         return;
2791                 
2792                 // Line to send to players
2793                 std::wstring line;
2794                 // Whether to send to the player that sent the line
2795                 bool send_to_sender = false;
2796                 // Whether to send to other players
2797                 bool send_to_others = false;
2798                 
2799                 // Local player gets all privileges regardless of
2800                 // what's set on their account.
2801                 u64 privs = getPlayerPrivs(player);
2802
2803                 // Parse commands
2804                 if(message[0] == L'/')
2805                 {
2806                         size_t strip_size = 1;
2807                         if (message[1] == L'#') // support old-style commans
2808                                 ++strip_size;
2809                         message = message.substr(strip_size);
2810
2811                         WStrfnd f1(message);
2812                         f1.next(L" "); // Skip over /#whatever
2813                         std::wstring paramstring = f1.next(L"");
2814
2815                         ServerCommandContext *ctx = new ServerCommandContext(
2816                                 str_split(message, L' '),
2817                                 paramstring,
2818                                 this,
2819                                 m_env,
2820                                 player,
2821                                 privs);
2822
2823                         std::wstring reply(processServerCommand(ctx));
2824                         send_to_sender = ctx->flags & SEND_TO_SENDER;
2825                         send_to_others = ctx->flags & SEND_TO_OTHERS;
2826
2827                         if (ctx->flags & SEND_NO_PREFIX)
2828                                 line += reply;
2829                         else
2830                                 line += L"Server: " + reply;
2831
2832                         delete ctx;
2833
2834                 }
2835                 else
2836                 {
2837                         if(privs & PRIV_SHOUT)
2838                         {
2839                                 line += L"<";
2840                                 line += name;
2841                                 line += L"> ";
2842                                 line += message;
2843                                 send_to_others = true;
2844                         }
2845                         else
2846                         {
2847                                 line += L"Server: You are not allowed to shout";
2848                                 send_to_sender = true;
2849                         }
2850                 }
2851                 
2852                 if(line != L"")
2853                 {
2854                         if(send_to_others)
2855                                 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2856
2857                         /*
2858                                 Send the message to clients
2859                         */
2860                         for(core::map<u16, RemoteClient*>::Iterator
2861                                 i = m_clients.getIterator();
2862                                 i.atEnd() == false; i++)
2863                         {
2864                                 // Get client and check that it is valid
2865                                 RemoteClient *client = i.getNode()->getValue();
2866                                 assert(client->peer_id == i.getNode()->getKey());
2867                                 if(client->serialization_version == SER_FMT_VER_INVALID)
2868                                         continue;
2869
2870                                 // Filter recipient
2871                                 bool sender_selected = (peer_id == client->peer_id);
2872                                 if(sender_selected == true && send_to_sender == false)
2873                                         continue;
2874                                 if(sender_selected == false && send_to_others == false)
2875                                         continue;
2876
2877                                 SendChatMessage(client->peer_id, line);
2878                         }
2879                 }
2880         }
2881         else if(command == TOSERVER_DAMAGE)
2882         {
2883                 std::string datastring((char*)&data[2], datasize-2);
2884                 std::istringstream is(datastring, std::ios_base::binary);
2885                 u8 damage = readU8(is);
2886
2887                 if(g_settings->getBool("enable_damage"))
2888                 {
2889                         actionstream<<player->getName()<<" damaged by "
2890                                         <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2891                                         <<std::endl;
2892                                 
2893                         HandlePlayerHP(player, damage);
2894                 }
2895                 else
2896                 {
2897                         SendPlayerHP(player);
2898                 }
2899         }
2900         else if(command == TOSERVER_PASSWORD)
2901         {
2902                 /*
2903                         [0] u16 TOSERVER_PASSWORD
2904                         [2] u8[28] old password
2905                         [30] u8[28] new password
2906                 */
2907
2908                 if(datasize != 2+PASSWORD_SIZE*2)
2909                         return;
2910                 /*char password[PASSWORD_SIZE];
2911                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2912                         password[i] = data[2+i];
2913                 password[PASSWORD_SIZE-1] = 0;*/
2914                 std::string oldpwd;
2915                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2916                 {
2917                         char c = data[2+i];
2918                         if(c == 0)
2919                                 break;
2920                         oldpwd += c;
2921                 }
2922                 std::string newpwd;
2923                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2924                 {
2925                         char c = data[2+PASSWORD_SIZE+i];
2926                         if(c == 0)
2927                                 break;
2928                         newpwd += c;
2929                 }
2930
2931                 infostream<<"Server: Client requests a password change from "
2932                                 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2933
2934                 std::string playername = player->getName();
2935
2936                 if(m_authmanager.exists(playername) == false)
2937                 {
2938                         infostream<<"Server: playername not found in authmanager"<<std::endl;
2939                         // Wrong old password supplied!!
2940                         SendChatMessage(peer_id, L"playername not found in authmanager");
2941                         return;
2942                 }
2943
2944                 std::string checkpwd = m_authmanager.getPassword(playername);
2945
2946                 if(oldpwd != checkpwd)
2947                 {
2948                         infostream<<"Server: invalid old password"<<std::endl;
2949                         // Wrong old password supplied!!
2950                         SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2951                         return;
2952                 }
2953
2954                 actionstream<<player->getName()<<" changes password"<<std::endl;
2955
2956                 m_authmanager.setPassword(playername, newpwd);
2957                 
2958                 infostream<<"Server: password change successful for "<<playername
2959                                 <<std::endl;
2960                 SendChatMessage(peer_id, L"Password change successful");
2961         }
2962         else if(command == TOSERVER_PLAYERITEM)
2963         {
2964                 if (datasize < 2+2)
2965                         return;
2966
2967                 u16 item = readU16(&data[2]);
2968                 player->wieldItem(item);
2969                 SendWieldedItem(player);
2970         }
2971         else if(command == TOSERVER_RESPAWN)
2972         {
2973                 if(player->hp != 0)
2974                         return;
2975                 
2976                 RespawnPlayer(player);
2977                 
2978                 actionstream<<player->getName()<<" respawns at "
2979                                 <<PP(player->getPosition()/BS)<<std::endl;
2980         }
2981         else if(command == TOSERVER_INTERACT)
2982         {
2983                 std::string datastring((char*)&data[2], datasize-2);
2984                 std::istringstream is(datastring, std::ios_base::binary);
2985
2986                 /*
2987                         [0] u16 command
2988                         [2] u8 action
2989                         [3] u16 item
2990                         [5] u32 length of the next item
2991                         [9] serialized PointedThing
2992                         actions:
2993                         0: start digging (from undersurface) or use
2994                         1: stop digging (all parameters ignored)
2995                         2: digging completed
2996                         3: place block or item (to abovesurface)
2997                         4: use item
2998                 */
2999                 u8 action = readU8(is);
3000                 u16 item_i = readU16(is);
3001                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
3002                 PointedThing pointed;
3003                 pointed.deSerialize(tmp_is);
3004
3005                 infostream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="<<item_i<<", pointed="<<pointed.dump()<<std::endl;
3006
3007                 v3f player_pos = srp->m_last_good_position;
3008
3009                 // Update wielded item
3010                 srp->wieldItem(item_i);
3011
3012                 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
3013                 v3s16 p_under = pointed.node_undersurface;
3014                 v3s16 p_above = pointed.node_abovesurface;
3015
3016                 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
3017                 ServerActiveObject *pointed_object = NULL;
3018                 if(pointed.type == POINTEDTHING_OBJECT)
3019                 {
3020                         pointed_object = m_env->getActiveObject(pointed.object_id);
3021                         if(pointed_object == NULL)
3022                         {
3023                                 infostream<<"TOSERVER_INTERACT: "
3024                                         "pointed object is NULL"<<std::endl;
3025                                 return;
3026                         }
3027
3028                 }
3029
3030                 /*
3031                         Check that target is reasonably close
3032                         (only when digging or placing things)
3033                 */
3034                 if(action == 0 || action == 2 || action == 3)
3035                 {
3036                         v3f pointed_pos = player_pos;
3037                         if(pointed.type == POINTEDTHING_NODE)
3038                         {
3039                                 pointed_pos = intToFloat(p_under, BS);
3040                         }
3041                         else if(pointed.type == POINTEDTHING_OBJECT)
3042                         {
3043                                 pointed_pos = pointed_object->getBasePosition();
3044                         }
3045
3046                         float d = player_pos.getDistanceFrom(pointed_pos);
3047                         float max_d = BS * 10; // Just some large enough value
3048                         if(d > max_d){
3049                                 actionstream<<"Player "<<player->getName()
3050                                                 <<" tried to access "<<pointed.dump()
3051                                                 <<" from too far: "
3052                                                 <<"d="<<d<<", max_d="<<max_d
3053                                                 <<". ignoring."<<std::endl;
3054                                 // Re-send block to revert change on client-side
3055                                 RemoteClient *client = getClient(peer_id);
3056                                 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos, BS));
3057                                 client->SetBlockNotSent(blockpos);
3058                                 // Do nothing else
3059                                 return;
3060                         }
3061                 }
3062
3063                 /*
3064                         Make sure the player is allowed to do it
3065                 */
3066                 bool build_priv = (getPlayerPrivs(player) & PRIV_BUILD) != 0;
3067                 if(!build_priv)
3068                 {
3069                         infostream<<"Ignoring interaction from player "<<player->getName()
3070                                         <<" because privileges are "<<getPlayerPrivs(player)
3071                                         <<std::endl;
3072                         // NOTE: no return; here, fall through
3073                 }
3074
3075                 /*
3076                         0: start digging or punch object
3077                 */
3078                 if(action == 0)
3079                 {
3080                         if(pointed.type == POINTEDTHING_NODE)
3081                         {
3082                                 /*
3083                                         NOTE: This can be used in the future to check if
3084                                         somebody is cheating, by checking the timing.
3085                                 */
3086                                 bool cannot_punch_node = !build_priv;
3087
3088                                 MapNode n(CONTENT_IGNORE);
3089
3090                                 try
3091                                 {
3092                                         n = m_env->getMap().getNode(p_under);
3093                                 }
3094                                 catch(InvalidPositionException &e)
3095                                 {
3096                                         infostream<<"Server: Not punching: Node not found."
3097                                                         <<" Adding block to emerge queue."
3098                                                         <<std::endl;
3099                                         m_emerge_queue.addBlock(peer_id,
3100                                                         getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3101                                         cannot_punch_node = true;
3102                                 }
3103
3104                                 if(cannot_punch_node)
3105                                         return;
3106
3107                                 /*
3108                                         Run script hook
3109                                 */
3110                                 scriptapi_environment_on_punchnode(m_lua, p_under, n, srp);
3111                         }
3112                         else if(pointed.type == POINTEDTHING_OBJECT)
3113                         {
3114                                 if(!build_priv)
3115                                         return;
3116
3117                                 // Skip if object has been removed
3118                                 if(pointed_object->m_removed)
3119                                         return;
3120
3121                                 actionstream<<player->getName()<<" punches object "
3122                                         <<pointed.object_id<<std::endl;
3123
3124                                 // Do stuff
3125                                 pointed_object->punch(srp);
3126                         }
3127
3128                 } // action == 0
3129
3130                 /*
3131                         1: stop digging
3132                 */
3133                 else if(action == 1)
3134                 {
3135                 } // action == 1
3136
3137                 /*
3138                         2: Digging completed
3139                 */
3140                 else if(action == 2)
3141                 {
3142                         // Only complete digging of nodes
3143                         if(pointed.type != POINTEDTHING_NODE)
3144                                 return;
3145
3146                         // Mandatory parameter; actually used for nothing
3147                         core::map<v3s16, MapBlock*> modified_blocks;
3148
3149                         content_t material = CONTENT_IGNORE;
3150                         u8 mineral = MINERAL_NONE;
3151
3152                         bool cannot_remove_node = !build_priv;
3153                         
3154                         MapNode n(CONTENT_IGNORE);
3155                         try
3156                         {
3157                                 n = m_env->getMap().getNode(p_under);
3158                                 // Get mineral
3159                                 mineral = n.getMineral(m_nodedef);
3160                                 // Get material at position
3161                                 material = n.getContent();
3162                                 // If not yet cancelled
3163                                 if(cannot_remove_node == false)
3164                                 {
3165                                         // If it's not diggable, do nothing
3166                                         if(m_nodedef->get(material).diggable == false)
3167                                         {
3168                                                 infostream<<"Server: Not finishing digging: "
3169                                                                 <<"Node not diggable"
3170                                                                 <<std::endl;
3171                                                 cannot_remove_node = true;
3172                                         }
3173                                 }
3174                                 // If not yet cancelled
3175                                 if(cannot_remove_node == false)
3176                                 {
3177                                         // Get node metadata
3178                                         NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under);
3179                                         if(meta && meta->nodeRemovalDisabled() == true)
3180                                         {
3181                                                 infostream<<"Server: Not finishing digging: "
3182                                                                 <<"Node metadata disables removal"
3183                                                                 <<std::endl;
3184                                                 cannot_remove_node = true;
3185                                         }
3186                                 }
3187                         }
3188                         catch(InvalidPositionException &e)
3189                         {
3190                                 infostream<<"Server: Not finishing digging: Node not found."
3191                                                 <<" Adding block to emerge queue."
3192                                                 <<std::endl;
3193                                 m_emerge_queue.addBlock(peer_id,
3194                                                 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3195                                 cannot_remove_node = true;
3196                         }
3197
3198                         /*
3199                                 If node can't be removed, set block to be re-sent to
3200                                 client and quit.
3201                         */
3202                         if(cannot_remove_node)
3203                         {
3204                                 infostream<<"Server: Not finishing digging."<<std::endl;
3205
3206                                 // Client probably has wrong data.
3207                                 // Set block not sent, so that client will get
3208                                 // a valid one.
3209                                 infostream<<"Client "<<peer_id<<" tried to dig "
3210                                                 <<"node; but node cannot be removed."
3211                                                 <<" setting MapBlock not sent."<<std::endl;
3212                                 RemoteClient *client = getClient(peer_id);
3213                                 v3s16 blockpos = getNodeBlockPos(p_under);
3214                                 client->SetBlockNotSent(blockpos);
3215                                         
3216                                 return;
3217                         }
3218                         
3219                         actionstream<<player->getName()<<" digs "<<PP(p_under)
3220                                         <<", gets material "<<(int)material<<", mineral "
3221                                         <<(int)mineral<<std::endl;
3222                         
3223                         /*
3224                                 Send the removal to all close-by players.
3225                                 - If other player is close, send REMOVENODE
3226                                 - Otherwise set blocks not sent
3227                         */
3228                         core::list<u16> far_players;
3229                         sendRemoveNode(p_under, peer_id, &far_players, 30);
3230                         
3231                         /*
3232                                 Update and send inventory
3233                         */
3234
3235                         if(g_settings->getBool("creative_mode") == false)
3236                         {
3237                                 /*
3238                                         Wear out tool
3239                                 */
3240                                 InventoryList *mlist = player->inventory.getList("main");
3241                                 if(mlist != NULL)
3242                                 {
3243                                         InventoryItem *item = mlist->getItem(item_i);
3244                                         if(item && (std::string)item->getName() == "ToolItem")
3245                                         {
3246                                                 ToolItem *titem = (ToolItem*)item;
3247                                                 std::string toolname = titem->getToolName();
3248
3249                                                 // Get digging properties for material and tool
3250                                                 ToolDiggingProperties tp =
3251                                                                 m_toolmgr->getDiggingProperties(toolname);
3252                                                 DiggingProperties prop =
3253                                                                 getDiggingProperties(material, &tp, m_nodedef);
3254
3255                                                 if(prop.diggable == false)
3256                                                 {
3257                                                         infostream<<"Server: WARNING: Player digged"
3258                                                                         <<" with impossible material + tool"
3259                                                                         <<" combination"<<std::endl;
3260                                                 }
3261                                                 
3262                                                 bool weared_out = titem->addWear(prop.wear);
3263
3264                                                 if(weared_out)
3265                                                 {
3266                                                         mlist->deleteItem(item_i);
3267                                                 }
3268
3269                                                 srp->m_inventory_not_sent = true;
3270                                         }
3271                                 }
3272
3273                                 /*
3274                                         Add dug item to inventory
3275                                 */
3276
3277                                 InventoryItem *item = NULL;
3278
3279                                 if(mineral != MINERAL_NONE)
3280                                         item = getDiggedMineralItem(mineral, this);
3281                                 
3282                                 // If not mineral
3283                                 if(item == NULL)
3284                                 {
3285                                         const std::string &dug_s = m_nodedef->get(material).dug_item;
3286                                         if(dug_s != "")
3287                                         {
3288                                                 std::istringstream is(dug_s, std::ios::binary);
3289                                                 item = InventoryItem::deSerialize(is, this);
3290                                         }
3291                                 }
3292                                 
3293                                 if(item != NULL)
3294                                 {
3295                                         // Add a item to inventory
3296                                         player->inventory.addItem("main", item);
3297                                         srp->m_inventory_not_sent = true;
3298                                 }
3299
3300                                 item = NULL;
3301
3302                                 if(mineral != MINERAL_NONE)
3303                                         item = getDiggedMineralItem(mineral, this);
3304                         
3305                                 // If not mineral
3306                                 if(item == NULL)
3307                                 {
3308                                         const std::string &extra_dug_s = m_nodedef->get(material).extra_dug_item;
3309                                         s32 extra_rarity = m_nodedef->get(material).extra_dug_item_rarity;
3310                                         if(extra_dug_s != "" && extra_rarity != 0
3311                                            && myrand() % extra_rarity == 0)
3312                                         {
3313                                                 std::istringstream is(extra_dug_s, std::ios::binary);
3314                                                 item = InventoryItem::deSerialize(is, this);
3315                                         }
3316                                 }
3317                         
3318                                 if(item != NULL)
3319                                 {
3320                                         // Add a item to inventory
3321                                         player->inventory.addItem("main", item);
3322                                         srp->m_inventory_not_sent = true;
3323                                 }
3324                         }
3325
3326                         /*
3327                                 Remove the node
3328                                 (this takes some time so it is done after the quick stuff)
3329                         */
3330                         {
3331                                 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
3332
3333                                 m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks);
3334                         }
3335                         /*
3336                                 Set blocks not sent to far players
3337                         */
3338                         for(core::list<u16>::Iterator
3339                                         i = far_players.begin();
3340                                         i != far_players.end(); i++)
3341                         {
3342                                 u16 peer_id = *i;
3343                                 RemoteClient *client = getClient(peer_id);
3344                                 if(client==NULL)
3345                                         continue;
3346                                 client->SetBlocksNotSent(modified_blocks);
3347                         }
3348
3349                         /*
3350                                 Run script hook
3351                         */
3352                         scriptapi_environment_on_dignode(m_lua, p_under, n, srp);
3353                 } // action == 2
3354                 
3355                 /*
3356                         3: place block or right-click object
3357                 */
3358                 else if(action == 3)
3359                 {
3360                         if(pointed.type == POINTEDTHING_NODE)
3361                         {
3362                                 InventoryList *ilist = player->inventory.getList("main");
3363                                 if(ilist == NULL)
3364                                         return;
3365
3366                                 // Get item
3367                                 InventoryItem *item = ilist->getItem(item_i);
3368                                 
3369                                 // If there is no item, it is not possible to add it anywhere
3370                                 if(item == NULL)
3371                                         return;
3372
3373                                 /*
3374                                         Handle material items
3375                                 */
3376                                 if(std::string("MaterialItem") == item->getName())
3377                                 {
3378                                         bool cannot_place_node = !build_priv;
3379
3380                                         try{
3381                                                 // Don't add a node if this is not a free space
3382                                                 MapNode n2 = m_env->getMap().getNode(p_above);
3383                                                 if(m_nodedef->get(n2).buildable_to == false)
3384                                                 {
3385                                                         infostream<<"Client "<<peer_id<<" tried to place"
3386                                                                         <<" node in invalid position."<<std::endl;
3387                                                         cannot_place_node = true;
3388                                                 }
3389                                         }
3390                                         catch(InvalidPositionException &e)
3391                                         {
3392                                                 infostream<<"Server: Ignoring ADDNODE: Node not found"
3393                                                                 <<" Adding block to emerge queue."
3394                                                                 <<std::endl;
3395                                                 m_emerge_queue.addBlock(peer_id,
3396                                                                 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3397                                                 cannot_place_node = true;
3398                                         }
3399
3400                                         if(cannot_place_node)
3401                                         {
3402                                                 // Client probably has wrong data.
3403                                                 // Set block not sent, so that client will get
3404                                                 // a valid one.
3405                                                 RemoteClient *client = getClient(peer_id);
3406                                                 v3s16 blockpos = getNodeBlockPos(p_above);
3407                                                 client->SetBlockNotSent(blockpos);
3408                                                 return;
3409                                         }
3410
3411                                         // Reset build time counter
3412                                         getClient(peer_id)->m_time_from_building = 0.0;
3413                                         
3414                                         // Create node data
3415                                         MaterialItem *mitem = (MaterialItem*)item;
3416                                         MapNode n;
3417                                         n.setContent(mitem->getMaterial());
3418
3419                                         actionstream<<player->getName()<<" places material "
3420                                                         <<(int)mitem->getMaterial()
3421                                                         <<" at "<<PP(p_under)<<std::endl;
3422                                 
3423                                         // Calculate direction for wall mounted stuff
3424                                         if(m_nodedef->get(n).wall_mounted)
3425                                                 n.param2 = packDir(p_under - p_above);
3426
3427                                         // Calculate the direction for furnaces and chests and stuff
3428                                         if(m_nodedef->get(n).param_type == CPT_FACEDIR_SIMPLE)
3429                                         {
3430                                                 v3f playerpos = player->getPosition();
3431                                                 v3f blockpos = intToFloat(p_above, BS) - playerpos;
3432                                                 blockpos = blockpos.normalize();
3433                                                 n.param1 = 0;
3434                                                 if (fabs(blockpos.X) > fabs(blockpos.Z)) {
3435                                                         if (blockpos.X < 0)
3436                                                                 n.param1 = 3;
3437                                                         else
3438                                                                 n.param1 = 1;
3439                                                 } else {
3440                                                         if (blockpos.Z < 0)
3441                                                                 n.param1 = 2;
3442                                                         else
3443                                                                 n.param1 = 0;
3444                                                 }
3445                                         }
3446
3447                                         /*
3448                                                 Send to all close-by players
3449                                         */
3450                                         core::list<u16> far_players;
3451                                         sendAddNode(p_above, n, 0, &far_players, 30);
3452                                         
3453                                         /*
3454                                                 Handle inventory
3455                                         */
3456                                         InventoryList *ilist = player->inventory.getList("main");
3457                                         if(g_settings->getBool("creative_mode") == false && ilist)
3458                                         {
3459                                                 // Remove from inventory and send inventory
3460                                                 if(mitem->getCount() <= 1)
3461                                                         ilist->deleteItem(item_i);
3462                                                 else
3463                                                         mitem->remove(1);
3464                                                 srp->m_inventory_not_sent = true;
3465                                         }
3466                                         
3467                                         /*
3468                                                 Add node.
3469
3470                                                 This takes some time so it is done after the quick stuff
3471                                         */
3472                                         core::map<v3s16, MapBlock*> modified_blocks;
3473                                         {
3474                                                 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
3475
3476                                                 std::string p_name = std::string(player->getName());
3477                                                 m_env->getMap().addNodeAndUpdate(p_above, n, modified_blocks, p_name);
3478                                         }
3479                                         /*
3480                                                 Set blocks not sent to far players
3481                                         */
3482                                         for(core::list<u16>::Iterator
3483                                                         i = far_players.begin();
3484                                                         i != far_players.end(); i++)
3485                                         {
3486                                                 u16 peer_id = *i;
3487                                                 RemoteClient *client = getClient(peer_id);
3488                                                 if(client==NULL)
3489                                                         continue;
3490                                                 client->SetBlocksNotSent(modified_blocks);
3491                                         }
3492
3493                                         /*
3494                                                 Run script hook
3495                                         */
3496                                         scriptapi_environment_on_placenode(m_lua, p_above, n, srp);
3497
3498                                         /*
3499                                                 Calculate special events
3500                                         */
3501                                         
3502                                         /*if(n.d == LEGN(m_nodedef, "CONTENT_MESE"))
3503                                         {
3504                                                 u32 count = 0;
3505                                                 for(s16 z=-1; z<=1; z++)
3506                                                 for(s16 y=-1; y<=1; y++)
3507                                                 for(s16 x=-1; x<=1; x++)
3508                                                 {
3509                                                         
3510                                                 }
3511                                         }*/
3512                                 }
3513                                 /*
3514                                         Place other item (not a block)
3515                                 */
3516                                 else
3517                                 {
3518                                         if(!build_priv)
3519                                         {
3520                                                 infostream<<"Not allowing player to place item: "
3521                                                                 "no build privileges"<<std::endl;
3522                                                 return;
3523                                         }
3524
3525                                         // Calculate a position for it
3526                                         v3f pos = player_pos;
3527                                         if(pointed.type == POINTEDTHING_NOTHING)
3528                                         {
3529                                                 infostream<<"Not allowing player to place item: "
3530                                                                 "pointing to nothing"<<std::endl;
3531                                                 return;
3532                                         }
3533                                         else if(pointed.type == POINTEDTHING_NODE)
3534                                         {
3535                                                 pos = intToFloat(p_above, BS);
3536                                         }
3537                                         else if(pointed.type == POINTEDTHING_OBJECT)
3538                                         {
3539                                                 pos = pointed_object->getBasePosition();
3540
3541                                                 // Randomize a bit
3542                                                 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
3543                                                 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
3544                                         }
3545
3546                                         //pos.Y -= BS*0.45;
3547                                         //pos.Y -= BS*0.25; // let it drop a bit
3548
3549                                         /*
3550                                                 Check that the block is loaded so that the item
3551                                                 can properly be added to the static list too
3552                                         */
3553                                         v3s16 blockpos = getNodeBlockPos(floatToInt(pos, BS));
3554                                         MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3555                                         if(block==NULL)
3556                                         {
3557                                                 infostream<<"Error while placing item: "
3558                                                                 "block not found"<<std::endl;
3559                                                 return;
3560                                         }
3561
3562                                         actionstream<<player->getName()<<" places "<<item->getName()
3563                                                         <<" at "<<PP(pos)<<std::endl;
3564
3565                                         /*
3566                                                 Place the item
3567                                         */
3568                                         bool remove = item->dropOrPlace(m_env, srp, pos, true, -1);
3569                                         if(remove && g_settings->getBool("creative_mode") == false)
3570                                         {
3571                                                 InventoryList *ilist = player->inventory.getList("main");
3572                                                 if(ilist){
3573                                                         // Remove from inventory and send inventory
3574                                                         ilist->deleteItem(item_i);
3575                                                         srp->m_inventory_not_sent = true;
3576                                                 }
3577                                         }
3578                                 }
3579                         }
3580                         else if(pointed.type == POINTEDTHING_OBJECT)
3581                         {
3582                                 // Right click object
3583
3584                                 if(!build_priv)
3585                                         return;
3586
3587                                 // Skip if object has been removed
3588                                 if(pointed_object->m_removed)
3589                                         return;
3590
3591                                 actionstream<<player->getName()<<" right-clicks object "
3592                                         <<pointed.object_id<<std::endl;
3593
3594                                 // Do stuff
3595                                 pointed_object->rightClick(srp);
3596                         }
3597
3598                 } // action == 3
3599
3600                 /*
3601                         4: use
3602                 */
3603                 else if(action == 4)
3604                 {
3605                         InventoryList *ilist = player->inventory.getList("main");
3606                         if(ilist == NULL)
3607                                 return;
3608
3609                         // Get item
3610                         InventoryItem *item = ilist->getItem(item_i);
3611                         
3612                         // If there is no item, it is not possible to add it anywhere
3613                         if(item == NULL)
3614                                 return;
3615
3616                         // Requires build privs
3617                         if(!build_priv)
3618                         {
3619                                 infostream<<"Not allowing player to use item: "
3620                                                 "no build privileges"<<std::endl;
3621                                 return;
3622                         }
3623
3624                         actionstream<<player->getName()<<" uses "<<item->getName()
3625                                         <<", pointing at "<<pointed.dump()<<std::endl;
3626
3627                         bool remove = item->use(m_env, srp, pointed);
3628                         
3629                         if(remove && g_settings->getBool("creative_mode") == false)
3630                         {
3631                                 InventoryList *ilist = player->inventory.getList("main");
3632                                 if(ilist){
3633                                         // Remove from inventory and send inventory
3634                                         ilist->deleteItem(item_i);
3635                                         srp->m_inventory_not_sent = true;
3636                                 }
3637                         }
3638
3639                 } // action == 4
3640
3641                 /*
3642                         Catch invalid actions
3643                 */
3644                 else
3645                 {
3646                         infostream<<"WARNING: Server: Invalid action "
3647                                         <<action<<std::endl;
3648                 }
3649
3650                 // Complete add_to_inventory_later
3651                 srp->completeAddToInventoryLater(item_i);
3652         }
3653         else
3654         {
3655                 infostream<<"Server::ProcessData(): Ignoring "
3656                                 "unknown command "<<command<<std::endl;
3657         }
3658         
3659         } //try
3660         catch(SendFailedException &e)
3661         {
3662                 errorstream<<"Server::ProcessData(): SendFailedException: "
3663                                 <<"what="<<e.what()
3664                                 <<std::endl;
3665         }
3666 }
3667
3668 void Server::onMapEditEvent(MapEditEvent *event)
3669 {
3670         //infostream<<"Server::onMapEditEvent()"<<std::endl;
3671         if(m_ignore_map_edit_events)
3672                 return;
3673         MapEditEvent *e = event->clone();
3674         m_unsent_map_edit_queue.push_back(e);
3675 }
3676
3677 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3678 {
3679         if(id == "current_player")
3680         {
3681                 assert(c->current_player);
3682                 return &(c->current_player->inventory);
3683         }
3684         
3685         Strfnd fn(id);
3686         std::string id0 = fn.next(":");
3687
3688         if(id0 == "nodemeta")
3689         {
3690                 v3s16 p;
3691                 p.X = stoi(fn.next(","));
3692                 p.Y = stoi(fn.next(","));
3693                 p.Z = stoi(fn.next(","));
3694                 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3695                 if(meta)
3696                         return meta->getInventory();
3697                 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3698                                 <<"no metadata found"<<std::endl;
3699                 return NULL;
3700         }
3701
3702         infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3703         return NULL;
3704 }
3705 void Server::inventoryModified(InventoryContext *c, std::string id)
3706 {
3707         if(id == "current_player")
3708         {
3709                 assert(c->current_player);
3710                 ServerRemotePlayer *srp =
3711                                 static_cast<ServerRemotePlayer*>(c->current_player);
3712                 srp->m_inventory_not_sent = true;
3713                 return;
3714         }
3715         
3716         Strfnd fn(id);
3717         std::string id0 = fn.next(":");
3718
3719         if(id0 == "nodemeta")
3720         {
3721                 v3s16 p;
3722                 p.X = stoi(fn.next(","));
3723                 p.Y = stoi(fn.next(","));
3724                 p.Z = stoi(fn.next(","));
3725                 v3s16 blockpos = getNodeBlockPos(p);
3726
3727                 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3728                 if(meta)
3729                         meta->inventoryModified();
3730                 
3731                 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3732                 if(block)
3733                         block->raiseModified(MOD_STATE_WRITE_NEEDED);
3734                 
3735                 setBlockNotSent(blockpos);
3736
3737                 return;
3738         }
3739
3740         infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3741 }
3742
3743 core::list<PlayerInfo> Server::getPlayerInfo()
3744 {
3745         DSTACK(__FUNCTION_NAME);
3746         JMutexAutoLock envlock(m_env_mutex);
3747         JMutexAutoLock conlock(m_con_mutex);
3748         
3749         core::list<PlayerInfo> list;
3750
3751         core::list<Player*> players = m_env->getPlayers();
3752         
3753         core::list<Player*>::Iterator i;
3754         for(i = players.begin();
3755                         i != players.end(); i++)
3756         {
3757                 PlayerInfo info;
3758
3759                 Player *player = *i;
3760
3761                 try{
3762                         // Copy info from connection to info struct
3763                         info.id = player->peer_id;
3764                         info.address = m_con.GetPeerAddress(player->peer_id);
3765                         info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3766                 }
3767                 catch(con::PeerNotFoundException &e)
3768                 {
3769                         // Set dummy peer info
3770                         info.id = 0;
3771                         info.address = Address(0,0,0,0,0);
3772                         info.avg_rtt = 0.0;
3773                 }
3774
3775                 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3776                 info.position = player->getPosition();
3777
3778                 list.push_back(info);
3779         }
3780
3781         return list;
3782 }
3783
3784
3785 void Server::peerAdded(con::Peer *peer)
3786 {
3787         DSTACK(__FUNCTION_NAME);
3788         infostream<<"Server::peerAdded(): peer->id="
3789                         <<peer->id<<std::endl;
3790         
3791         PeerChange c;
3792         c.type = PEER_ADDED;
3793         c.peer_id = peer->id;
3794         c.timeout = false;
3795         m_peer_change_queue.push_back(c);
3796 }
3797
3798 void Server::deletingPeer(con::Peer *peer, bool timeout)
3799 {
3800         DSTACK(__FUNCTION_NAME);
3801         infostream<<"Server::deletingPeer(): peer->id="
3802                         <<peer->id<<", timeout="<<timeout<<std::endl;
3803         
3804         PeerChange c;
3805         c.type = PEER_REMOVED;
3806         c.peer_id = peer->id;
3807         c.timeout = timeout;
3808         m_peer_change_queue.push_back(c);
3809 }
3810
3811 /*
3812         Static send methods
3813 */
3814
3815 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3816 {
3817         DSTACK(__FUNCTION_NAME);
3818         std::ostringstream os(std::ios_base::binary);
3819
3820         writeU16(os, TOCLIENT_HP);
3821         writeU8(os, hp);
3822
3823         // Make data buffer
3824         std::string s = os.str();
3825         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3826         // Send as reliable
3827         con.Send(peer_id, 0, data, true);
3828 }
3829
3830 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3831                 const std::wstring &reason)
3832 {
3833         DSTACK(__FUNCTION_NAME);
3834         std::ostringstream os(std::ios_base::binary);
3835
3836         writeU16(os, TOCLIENT_ACCESS_DENIED);
3837         os<<serializeWideString(reason);
3838
3839         // Make data buffer
3840         std::string s = os.str();
3841         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3842         // Send as reliable
3843         con.Send(peer_id, 0, data, true);
3844 }
3845
3846 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3847                 bool set_camera_point_target, v3f camera_point_target)
3848 {
3849         DSTACK(__FUNCTION_NAME);
3850         std::ostringstream os(std::ios_base::binary);
3851
3852         writeU16(os, TOCLIENT_DEATHSCREEN);
3853         writeU8(os, set_camera_point_target);
3854         writeV3F1000(os, camera_point_target);
3855
3856         // Make data buffer
3857         std::string s = os.str();
3858         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3859         // Send as reliable
3860         con.Send(peer_id, 0, data, true);
3861 }
3862
3863 void Server::SendToolDef(con::Connection &con, u16 peer_id,
3864                 IToolDefManager *tooldef)
3865 {
3866         DSTACK(__FUNCTION_NAME);
3867         std::ostringstream os(std::ios_base::binary);
3868
3869         /*
3870                 u16 command
3871                 u32 length of the next item
3872                 serialized ToolDefManager
3873         */
3874         writeU16(os, TOCLIENT_TOOLDEF);
3875         std::ostringstream tmp_os(std::ios::binary);
3876         tooldef->serialize(tmp_os);
3877         os<<serializeLongString(tmp_os.str());
3878
3879         // Make data buffer
3880         std::string s = os.str();
3881         infostream<<"Server::SendToolDef(): Sending tool definitions: size="
3882                         <<s.size()<<std::endl;
3883         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3884         // Send as reliable
3885         con.Send(peer_id, 0, data, true);
3886 }
3887
3888 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3889                 INodeDefManager *nodedef)
3890 {
3891         DSTACK(__FUNCTION_NAME);
3892         std::ostringstream os(std::ios_base::binary);
3893
3894         /*
3895                 u16 command
3896                 u32 length of the next item
3897                 serialized NodeDefManager
3898         */
3899         writeU16(os, TOCLIENT_NODEDEF);
3900         std::ostringstream tmp_os(std::ios::binary);
3901         nodedef->serialize(tmp_os);
3902         os<<serializeLongString(tmp_os.str());
3903
3904         // Make data buffer
3905         std::string s = os.str();
3906         infostream<<"Server::SendNodeDef(): Sending node definitions: size="
3907                         <<s.size()<<std::endl;
3908         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3909         // Send as reliable
3910         con.Send(peer_id, 0, data, true);
3911 }
3912
3913 void Server::SendCraftItemDef(con::Connection &con, u16 peer_id,
3914                 ICraftItemDefManager *craftitemdef)
3915 {
3916         DSTACK(__FUNCTION_NAME);
3917         std::ostringstream os(std::ios_base::binary);
3918
3919         /*
3920                 u16 command
3921                 u32 length of the next item
3922                 serialized CraftItemDefManager
3923         */
3924         writeU16(os, TOCLIENT_CRAFTITEMDEF);
3925         std::ostringstream tmp_os(std::ios::binary);
3926         craftitemdef->serialize(tmp_os);
3927         os<<serializeLongString(tmp_os.str());
3928
3929         // Make data buffer
3930         std::string s = os.str();
3931         infostream<<"Server::SendCraftItemDef(): Sending craft item definitions: size="
3932                         <<s.size()<<std::endl;
3933         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3934         // Send as reliable
3935         con.Send(peer_id, 0, data, true);
3936 }
3937
3938 /*
3939         Non-static send methods
3940 */
3941
3942 void Server::SendObjectData(float dtime)
3943 {
3944         DSTACK(__FUNCTION_NAME);
3945
3946         core::map<v3s16, bool> stepped_blocks;
3947         
3948         for(core::map<u16, RemoteClient*>::Iterator
3949                 i = m_clients.getIterator();
3950                 i.atEnd() == false; i++)
3951         {
3952                 u16 peer_id = i.getNode()->getKey();
3953                 RemoteClient *client = i.getNode()->getValue();
3954                 assert(client->peer_id == peer_id);
3955                 
3956                 if(client->serialization_version == SER_FMT_VER_INVALID)
3957                         continue;
3958                 
3959                 client->SendObjectData(this, dtime, stepped_blocks);
3960         }
3961 }
3962
3963 void Server::SendPlayerInfos()
3964 {
3965         DSTACK(__FUNCTION_NAME);
3966
3967         //JMutexAutoLock envlock(m_env_mutex);
3968         
3969         // Get connected players
3970         core::list<Player*> players = m_env->getPlayers(true);
3971         
3972         u32 player_count = players.getSize();
3973         u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3974
3975         SharedBuffer<u8> data(datasize);
3976         writeU16(&data[0], TOCLIENT_PLAYERINFO);
3977         
3978         u32 start = 2;
3979         core::list<Player*>::Iterator i;
3980         for(i = players.begin();
3981                         i != players.end(); i++)
3982         {
3983                 Player *player = *i;
3984
3985                 /*infostream<<"Server sending player info for player with "
3986                                 "peer_id="<<player->peer_id<<std::endl;*/
3987                 
3988                 writeU16(&data[start], player->peer_id);
3989                 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3990                 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3991                 start += 2+PLAYERNAME_SIZE;
3992         }
3993
3994         //JMutexAutoLock conlock(m_con_mutex);
3995
3996         // Send as reliable
3997         m_con.SendToAll(0, data, true);
3998 }
3999
4000 void Server::SendInventory(u16 peer_id)
4001 {
4002         DSTACK(__FUNCTION_NAME);
4003         
4004         ServerRemotePlayer* player =
4005                         static_cast<ServerRemotePlayer*>(m_env->getPlayer(peer_id));
4006         assert(player);
4007
4008         player->m_inventory_not_sent = false;
4009
4010         /*
4011                 Serialize it
4012         */
4013
4014         std::ostringstream os;
4015         //os.imbue(std::locale("C"));
4016
4017         player->inventory.serialize(os);
4018
4019         std::string s = os.str();
4020         
4021         SharedBuffer<u8> data(s.size()+2);
4022         writeU16(&data[0], TOCLIENT_INVENTORY);
4023         memcpy(&data[2], s.c_str(), s.size());
4024         
4025         // Send as reliable
4026         m_con.Send(peer_id, 0, data, true);
4027 }
4028
4029 std::string getWieldedItemString(const Player *player)
4030 {
4031         const InventoryItem *item = player->getWieldItem();
4032         if (item == NULL)
4033                 return std::string("");
4034         std::ostringstream os(std::ios_base::binary);
4035         item->serialize(os);
4036         return os.str();
4037 }
4038
4039 void Server::SendWieldedItem(const Player* player)
4040 {
4041         DSTACK(__FUNCTION_NAME);
4042
4043         assert(player);
4044
4045         std::ostringstream os(std::ios_base::binary);
4046
4047         writeU16(os, TOCLIENT_PLAYERITEM);
4048         writeU16(os, 1);
4049         writeU16(os, player->peer_id);
4050         os<<serializeString(getWieldedItemString(player));
4051
4052         // Make data buffer
4053         std::string s = os.str();
4054         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4055
4056         m_con.SendToAll(0, data, true);
4057 }
4058
4059 void Server::SendPlayerItems()
4060 {
4061         DSTACK(__FUNCTION_NAME);
4062
4063         std::ostringstream os(std::ios_base::binary);
4064         core::list<Player *> players = m_env->getPlayers(true);
4065
4066         writeU16(os, TOCLIENT_PLAYERITEM);
4067         writeU16(os, players.size());
4068         core::list<Player *>::Iterator i;
4069         for(i = players.begin(); i != players.end(); ++i)
4070         {
4071                 Player *p = *i;
4072                 writeU16(os, p->peer_id);
4073                 os<<serializeString(getWieldedItemString(p));
4074         }
4075
4076         // Make data buffer
4077         std::string s = os.str();
4078         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4079
4080         m_con.SendToAll(0, data, true);
4081 }
4082
4083 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
4084 {
4085         DSTACK(__FUNCTION_NAME);
4086         
4087         std::ostringstream os(std::ios_base::binary);
4088         u8 buf[12];
4089         
4090         // Write command
4091         writeU16(buf, TOCLIENT_CHAT_MESSAGE);
4092         os.write((char*)buf, 2);
4093         
4094         // Write length
4095         writeU16(buf, message.size());
4096         os.write((char*)buf, 2);
4097         
4098         // Write string
4099         for(u32 i=0; i<message.size(); i++)
4100         {
4101                 u16 w = message[i];
4102                 writeU16(buf, w);
4103                 os.write((char*)buf, 2);
4104         }
4105         
4106         // Make data buffer
4107         std::string s = os.str();
4108         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4109         // Send as reliable
4110         m_con.Send(peer_id, 0, data, true);
4111 }
4112
4113 void Server::BroadcastChatMessage(const std::wstring &message)
4114 {
4115         for(core::map<u16, RemoteClient*>::Iterator
4116                 i = m_clients.getIterator();
4117                 i.atEnd() == false; i++)
4118         {
4119                 // Get client and check that it is valid
4120                 RemoteClient *client = i.getNode()->getValue();
4121                 assert(client->peer_id == i.getNode()->getKey());
4122                 if(client->serialization_version == SER_FMT_VER_INVALID)
4123                         continue;
4124
4125                 SendChatMessage(client->peer_id, message);
4126         }
4127 }
4128
4129 void Server::SendPlayerHP(Player *player)
4130 {
4131         SendHP(m_con, player->peer_id, player->hp);
4132 }
4133
4134 void Server::SendMovePlayer(Player *player)
4135 {
4136         DSTACK(__FUNCTION_NAME);
4137         std::ostringstream os(std::ios_base::binary);
4138
4139         writeU16(os, TOCLIENT_MOVE_PLAYER);
4140         writeV3F1000(os, player->getPosition());
4141         writeF1000(os, player->getPitch());
4142         writeF1000(os, player->getYaw());
4143         
4144         {
4145                 v3f pos = player->getPosition();
4146                 f32 pitch = player->getPitch();
4147                 f32 yaw = player->getYaw();
4148                 infostream<<"Server sending TOCLIENT_MOVE_PLAYER"
4149                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
4150                                 <<" pitch="<<pitch
4151                                 <<" yaw="<<yaw
4152                                 <<std::endl;
4153         }
4154
4155         // Make data buffer
4156         std::string s = os.str();
4157         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4158         // Send as reliable
4159         m_con.Send(player->peer_id, 0, data, true);
4160 }
4161
4162 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
4163         core::list<u16> *far_players, float far_d_nodes)
4164 {
4165         float maxd = far_d_nodes*BS;
4166         v3f p_f = intToFloat(p, BS);
4167
4168         // Create packet
4169         u32 replysize = 8;
4170         SharedBuffer<u8> reply(replysize);
4171         writeU16(&reply[0], TOCLIENT_REMOVENODE);
4172         writeS16(&reply[2], p.X);
4173         writeS16(&reply[4], p.Y);
4174         writeS16(&reply[6], p.Z);
4175
4176         for(core::map<u16, RemoteClient*>::Iterator
4177                 i = m_clients.getIterator();
4178                 i.atEnd() == false; i++)
4179         {
4180                 // Get client and check that it is valid
4181                 RemoteClient *client = i.getNode()->getValue();
4182                 assert(client->peer_id == i.getNode()->getKey());
4183                 if(client->serialization_version == SER_FMT_VER_INVALID)
4184                         continue;
4185
4186                 // Don't send if it's the same one
4187                 if(client->peer_id == ignore_id)
4188                         continue;
4189                 
4190                 if(far_players)
4191                 {
4192                         // Get player
4193                         Player *player = m_env->getPlayer(client->peer_id);
4194                         if(player)
4195                         {
4196                                 // If player is far away, only set modified blocks not sent
4197                                 v3f player_pos = player->getPosition();
4198                                 if(player_pos.getDistanceFrom(p_f) > maxd)
4199                                 {
4200                                         far_players->push_back(client->peer_id);
4201                                         continue;
4202                                 }
4203                         }
4204                 }
4205
4206                 // Send as reliable
4207                 m_con.Send(client->peer_id, 0, reply, true);
4208         }
4209 }
4210
4211 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4212                 core::list<u16> *far_players, float far_d_nodes)
4213 {
4214         float maxd = far_d_nodes*BS;
4215         v3f p_f = intToFloat(p, BS);
4216
4217         for(core::map<u16, RemoteClient*>::Iterator
4218                 i = m_clients.getIterator();
4219                 i.atEnd() == false; i++)
4220         {
4221                 // Get client and check that it is valid
4222                 RemoteClient *client = i.getNode()->getValue();
4223                 assert(client->peer_id == i.getNode()->getKey());
4224                 if(client->serialization_version == SER_FMT_VER_INVALID)
4225                         continue;
4226
4227                 // Don't send if it's the same one
4228                 if(client->peer_id == ignore_id)
4229                         continue;
4230
4231                 if(far_players)
4232                 {
4233                         // Get player
4234                         Player *player = m_env->getPlayer(client->peer_id);
4235                         if(player)
4236                         {
4237                                 // If player is far away, only set modified blocks not sent
4238                                 v3f player_pos = player->getPosition();
4239                                 if(player_pos.getDistanceFrom(p_f) > maxd)
4240                                 {
4241                                         far_players->push_back(client->peer_id);
4242                                         continue;
4243                                 }
4244                         }
4245                 }
4246
4247                 // Create packet
4248                 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4249                 SharedBuffer<u8> reply(replysize);
4250                 writeU16(&reply[0], TOCLIENT_ADDNODE);
4251                 writeS16(&reply[2], p.X);
4252                 writeS16(&reply[4], p.Y);
4253                 writeS16(&reply[6], p.Z);
4254                 n.serialize(&reply[8], client->serialization_version);
4255
4256                 // Send as reliable
4257                 m_con.Send(client->peer_id, 0, reply, true);
4258         }
4259 }
4260
4261 void Server::setBlockNotSent(v3s16 p)
4262 {
4263         for(core::map<u16, RemoteClient*>::Iterator
4264                 i = m_clients.getIterator();
4265                 i.atEnd()==false; i++)
4266         {
4267                 RemoteClient *client = i.getNode()->getValue();
4268                 client->SetBlockNotSent(p);
4269         }
4270 }
4271
4272 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4273 {
4274         DSTACK(__FUNCTION_NAME);
4275
4276         v3s16 p = block->getPos();
4277         
4278 #if 0
4279         // Analyze it a bit
4280         bool completely_air = true;
4281         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4282         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4283         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4284         {
4285                 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4286                 {
4287                         completely_air = false;
4288                         x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4289                 }
4290         }
4291
4292         // Print result
4293         infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4294         if(completely_air)
4295                 infostream<<"[completely air] ";
4296         infostream<<std::endl;
4297 #endif
4298
4299         /*
4300                 Create a packet with the block in the right format
4301         */
4302         
4303         std::ostringstream os(std::ios_base::binary);
4304         block->serialize(os, ver);
4305         std::string s = os.str();
4306         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4307
4308         u32 replysize = 8 + blockdata.getSize();
4309         SharedBuffer<u8> reply(replysize);
4310         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4311         writeS16(&reply[2], p.X);
4312         writeS16(&reply[4], p.Y);
4313         writeS16(&reply[6], p.Z);
4314         memcpy(&reply[8], *blockdata, blockdata.getSize());
4315
4316         /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4317                         <<":  \tpacket size: "<<replysize<<std::endl;*/
4318         
4319         /*
4320                 Send packet
4321         */
4322         m_con.Send(peer_id, 1, reply, true);
4323 }
4324
4325 void Server::SendBlocks(float dtime)
4326 {
4327         DSTACK(__FUNCTION_NAME);
4328
4329         JMutexAutoLock envlock(m_env_mutex);
4330         JMutexAutoLock conlock(m_con_mutex);
4331
4332         //TimeTaker timer("Server::SendBlocks");
4333
4334         core::array<PrioritySortedBlockTransfer> queue;
4335
4336         s32 total_sending = 0;
4337         
4338         {
4339                 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4340
4341                 for(core::map<u16, RemoteClient*>::Iterator
4342                         i = m_clients.getIterator();
4343                         i.atEnd() == false; i++)
4344                 {
4345                         RemoteClient *client = i.getNode()->getValue();
4346                         assert(client->peer_id == i.getNode()->getKey());
4347
4348                         total_sending += client->SendingCount();
4349                         
4350                         if(client->serialization_version == SER_FMT_VER_INVALID)
4351                                 continue;
4352                         
4353                         client->GetNextBlocks(this, dtime, queue);
4354                 }
4355         }
4356
4357         // Sort.
4358         // Lowest priority number comes first.
4359         // Lowest is most important.
4360         queue.sort();
4361
4362         for(u32 i=0; i<queue.size(); i++)
4363         {
4364                 //TODO: Calculate limit dynamically
4365                 if(total_sending >= g_settings->getS32
4366                                 ("max_simultaneous_block_sends_server_total"))
4367                         break;
4368                 
4369                 PrioritySortedBlockTransfer q = queue[i];
4370
4371                 MapBlock *block = NULL;
4372                 try
4373                 {
4374                         block = m_env->getMap().getBlockNoCreate(q.pos);
4375                 }
4376                 catch(InvalidPositionException &e)
4377                 {
4378                         continue;
4379                 }
4380
4381                 RemoteClient *client = getClient(q.peer_id);
4382
4383                 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4384
4385                 client->SentBlock(q.pos);
4386
4387                 total_sending++;
4388         }
4389 }
4390
4391 struct SendableTexture
4392 {
4393         std::string name;
4394         std::string path;
4395         std::string data;
4396
4397         SendableTexture(const std::string &name_="", const std::string path_="",
4398                         const std::string &data_=""):
4399                 name(name_),
4400                 path(path_),
4401                 data(data_)
4402         {}
4403 };
4404
4405 void Server::SendTextures(u16 peer_id)
4406 {
4407         DSTACK(__FUNCTION_NAME);
4408
4409         infostream<<"Server::SendTextures(): Sending textures to client"<<std::endl;
4410         
4411         /* Read textures */
4412         
4413         // Put 5kB in one bunch (this is not accurate)
4414         u32 bytes_per_bunch = 5000;
4415         
4416         core::array< core::list<SendableTexture> > texture_bunches;
4417         texture_bunches.push_back(core::list<SendableTexture>());
4418         
4419         u32 texture_size_bunch_total = 0;
4420         core::list<ModSpec> mods = getMods(m_modspaths);
4421         for(core::list<ModSpec>::Iterator i = mods.begin();
4422                         i != mods.end(); i++){
4423                 ModSpec mod = *i;
4424                 std::string texturepath = mod.path + DIR_DELIM + "textures";
4425                 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(texturepath);
4426                 for(u32 j=0; j<dirlist.size(); j++){
4427                         if(dirlist[j].dir) // Ignode dirs
4428                                 continue;
4429                         std::string tname = dirlist[j].name;
4430                         std::string tpath = texturepath + DIR_DELIM + tname;
4431                         // Read data
4432                         std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4433                         if(fis.good() == false){
4434                                 errorstream<<"Server::SendTextures(): Could not open \""
4435                                                 <<tname<<"\" for reading"<<std::endl;
4436                                 continue;
4437                         }
4438                         std::ostringstream tmp_os(std::ios_base::binary);
4439                         bool bad = false;
4440                         for(;;){
4441                                 char buf[1024];
4442                                 fis.read(buf, 1024);
4443                                 std::streamsize len = fis.gcount();
4444                                 tmp_os.write(buf, len);
4445                                 texture_size_bunch_total += len;
4446                                 if(fis.eof())
4447                                         break;
4448                                 if(!fis.good()){
4449                                         bad = true;
4450                                         break;
4451                                 }
4452                         }
4453                         if(bad){
4454                                 errorstream<<"Server::SendTextures(): Failed to read \""
4455                                                 <<tname<<"\""<<std::endl;
4456                                 continue;
4457                         }
4458                         /*infostream<<"Server::SendTextures(): Loaded \""
4459                                         <<tname<<"\""<<std::endl;*/
4460                         // Put in list
4461                         texture_bunches[texture_bunches.size()-1].push_back(
4462                                         SendableTexture(tname, tpath, tmp_os.str()));
4463                         
4464                         // Start next bunch if got enough data
4465                         if(texture_size_bunch_total >= bytes_per_bunch){
4466                                 texture_bunches.push_back(core::list<SendableTexture>());
4467                                 texture_size_bunch_total = 0;
4468                         }
4469                 }
4470         }
4471
4472         /* Create and send packets */
4473         
4474         u32 num_bunches = texture_bunches.size();
4475         for(u32 i=0; i<num_bunches; i++)
4476         {
4477                 /*
4478                         u16 command
4479                         u16 total number of texture bunches
4480                         u16 index of this bunch
4481                         u32 number of textures in this bunch
4482                         for each texture {
4483                                 u16 length of name
4484                                 string name
4485                                 u32 length of data
4486                                 data
4487                         }
4488                 */
4489                 std::ostringstream os(std::ios_base::binary);
4490
4491                 writeU16(os, TOCLIENT_TEXTURES);
4492                 writeU16(os, num_bunches);
4493                 writeU16(os, i);
4494                 writeU32(os, texture_bunches[i].size());
4495                 
4496                 for(core::list<SendableTexture>::Iterator
4497                                 j = texture_bunches[i].begin();
4498                                 j != texture_bunches[i].end(); j++){
4499                         os<<serializeString(j->name);
4500                         os<<serializeLongString(j->data);
4501                 }
4502                 
4503                 // Make data buffer
4504                 std::string s = os.str();
4505                 infostream<<"Server::SendTextures(): bunch "<<i<<"/"<<num_bunches
4506                                 <<" textures="<<texture_bunches[i].size()
4507                                 <<" size=" <<s.size()<<std::endl;
4508                 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4509                 // Send as reliable
4510                 m_con.Send(peer_id, 0, data, true);
4511         }
4512 }
4513
4514 /*
4515         Something random
4516 */
4517
4518 void Server::HandlePlayerHP(Player *player, s16 damage)
4519 {
4520         if(player->hp > damage)
4521         {
4522                 player->hp -= damage;
4523                 SendPlayerHP(player);
4524         }
4525         else
4526         {
4527                 infostream<<"Server::HandlePlayerHP(): Player "
4528                                 <<player->getName()<<" dies"<<std::endl;
4529                 
4530                 player->hp = 0;
4531                 
4532                 //TODO: Throw items around
4533                 
4534                 // Handle players that are not connected
4535                 if(player->peer_id == PEER_ID_INEXISTENT){
4536                         RespawnPlayer(player);
4537                         return;
4538                 }
4539
4540                 SendPlayerHP(player);
4541                 
4542                 RemoteClient *client = getClient(player->peer_id);
4543                 if(client->net_proto_version >= 3)
4544                 {
4545                         SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4546                 }
4547                 else
4548                 {
4549                         RespawnPlayer(player);
4550                 }
4551         }
4552 }
4553
4554 void Server::RespawnPlayer(Player *player)
4555 {
4556         player->hp = 20;
4557         ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4558         bool repositioned = scriptapi_on_respawnplayer(m_lua, srp);
4559         if(!repositioned){
4560                 v3f pos = findSpawnPos(m_env->getServerMap());
4561                 player->setPosition(pos);
4562                 srp->m_last_good_position = pos;
4563                 srp->m_last_good_position_age = 0;
4564         }
4565         SendMovePlayer(player);
4566         SendPlayerHP(player);
4567 }
4568
4569 void Server::UpdateCrafting(u16 peer_id)
4570 {
4571         DSTACK(__FUNCTION_NAME);
4572         
4573         Player* player = m_env->getPlayer(peer_id);
4574         assert(player);
4575         ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4576
4577         // No crafting in creative mode
4578         if(g_settings->getBool("creative_mode"))
4579                 return;
4580         
4581         // Get the InventoryLists of the player in which we will operate
4582         InventoryList *clist = player->inventory.getList("craft");
4583         assert(clist);
4584         InventoryList *rlist = player->inventory.getList("craftresult");
4585         assert(rlist);
4586         InventoryList *mlist = player->inventory.getList("main");
4587         assert(mlist);
4588
4589         // If the result list is not a preview and is not empty, try to
4590         // throw the item into main list
4591         if(!player->craftresult_is_preview && rlist->getUsedSlots() != 0)
4592         {
4593                 // Grab item out of craftresult
4594                 InventoryItem *item = rlist->changeItem(0, NULL);
4595                 // Try to put in main
4596                 InventoryItem *leftover = mlist->addItem(item);
4597                 // If there are leftovers, put them back to craftresult and
4598                 // delete leftovers
4599                 delete rlist->addItem(leftover);
4600                 // Inventory was modified
4601                 srp->m_inventory_not_sent = true;
4602         }
4603         
4604         // If result list is empty, we will make it preview what would be
4605         // crafted
4606         if(rlist->getUsedSlots() == 0)
4607                 player->craftresult_is_preview = true;
4608         
4609         // If it is a preview, clear the possible old preview in it
4610         if(player->craftresult_is_preview)
4611                 rlist->clearItems();
4612
4613         // If it is a preview, find out what is the crafting result
4614         // and put it in
4615         if(player->craftresult_is_preview)
4616         {
4617                 // Mangle crafting grid to an another format
4618                 std::vector<InventoryItem*> items;
4619                 for(u16 i=0; i<9; i++){
4620                         if(clist->getItem(i) == NULL)
4621                                 items.push_back(NULL);
4622                         else
4623                                 items.push_back(clist->getItem(i)->clone());
4624                 }
4625                 CraftPointerInput cpi(3, items);
4626
4627                 // Find out what is crafted and add it to result item slot
4628                 InventoryItem *result = m_craftdef->getCraftResult(cpi, this);
4629                 if(result)
4630                         rlist->addItem(result);
4631         }
4632 }
4633
4634 RemoteClient* Server::getClient(u16 peer_id)
4635 {
4636         DSTACK(__FUNCTION_NAME);
4637         //JMutexAutoLock lock(m_con_mutex);
4638         core::map<u16, RemoteClient*>::Node *n;
4639         n = m_clients.find(peer_id);
4640         // A client should exist for all peers
4641         assert(n != NULL);
4642         return n->getValue();
4643 }
4644
4645 std::wstring Server::getStatusString()
4646 {
4647         std::wostringstream os(std::ios_base::binary);
4648         os<<L"# Server: ";
4649         // Version
4650         os<<L"version="<<narrow_to_wide(VERSION_STRING);
4651         // Uptime
4652         os<<L", uptime="<<m_uptime.get();
4653         // Information about clients
4654         os<<L", clients={";
4655         for(core::map<u16, RemoteClient*>::Iterator
4656                 i = m_clients.getIterator();
4657                 i.atEnd() == false; i++)
4658         {
4659                 // Get client and check that it is valid
4660                 RemoteClient *client = i.getNode()->getValue();
4661                 assert(client->peer_id == i.getNode()->getKey());
4662                 if(client->serialization_version == SER_FMT_VER_INVALID)
4663                         continue;
4664                 // Get player
4665                 Player *player = m_env->getPlayer(client->peer_id);
4666                 // Get name of player
4667                 std::wstring name = L"unknown";
4668                 if(player != NULL)
4669                         name = narrow_to_wide(player->getName());
4670                 // Add name to information string
4671                 os<<name<<L",";
4672         }
4673         os<<L"}";
4674         if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4675                 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4676         if(g_settings->get("motd") != "")
4677                 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4678         return os.str();
4679 }
4680
4681 // Saves g_settings to configpath given at initialization
4682 void Server::saveConfig()
4683 {
4684         if(m_configpath != "")
4685                 g_settings->updateConfigFile(m_configpath.c_str());
4686 }
4687
4688 void Server::notifyPlayer(const char *name, const std::wstring msg)
4689 {
4690         Player *player = m_env->getPlayer(name);
4691         if(!player)
4692                 return;
4693         SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4694 }
4695
4696 void Server::notifyPlayers(const std::wstring msg)
4697 {
4698         BroadcastChatMessage(msg);
4699 }
4700
4701 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4702 {
4703         u8 flags = 0;
4704         if(!allow_generate)
4705                 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4706         m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4707 }
4708
4709 // IGameDef interface
4710 // Under envlock
4711 IToolDefManager* Server::getToolDefManager()
4712 {
4713         return m_toolmgr;
4714 }
4715 INodeDefManager* Server::getNodeDefManager()
4716 {
4717         return m_nodedef;
4718 }
4719 ICraftDefManager* Server::getCraftDefManager()
4720 {
4721         return m_craftdef;
4722 }
4723 ICraftItemDefManager* Server::getCraftItemDefManager()
4724 {
4725         return m_craftitemdef;
4726 }
4727 ITextureSource* Server::getTextureSource()
4728 {
4729         return NULL;
4730 }
4731 u16 Server::allocateUnknownNodeId(const std::string &name)
4732 {
4733         return m_nodedef->allocateDummy(name);
4734 }
4735
4736 IWritableToolDefManager* Server::getWritableToolDefManager()
4737 {
4738         return m_toolmgr;
4739 }
4740 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4741 {
4742         return m_nodedef;
4743 }
4744 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4745 {
4746         return m_craftdef;
4747 }
4748 IWritableCraftItemDefManager* Server::getWritableCraftItemDefManager()
4749 {
4750         return m_craftitemdef;
4751 }
4752
4753 v3f findSpawnPos(ServerMap &map)
4754 {
4755         //return v3f(50,50,50)*BS;
4756
4757         v3s16 nodepos;
4758         
4759 #if 0
4760         nodepos = v2s16(0,0);
4761         groundheight = 20;
4762 #endif
4763
4764 #if 1
4765         // Try to find a good place a few times
4766         for(s32 i=0; i<1000; i++)
4767         {
4768                 s32 range = 1 + i;
4769                 // We're going to try to throw the player to this position
4770                 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4771                                 -range + (myrand()%(range*2)));
4772                 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4773                 // Get ground height at point (fallbacks to heightmap function)
4774                 s16 groundheight = map.findGroundLevel(nodepos2d);
4775                 // Don't go underwater
4776                 if(groundheight < WATER_LEVEL)
4777                 {
4778                         //infostream<<"-> Underwater"<<std::endl;
4779                         continue;
4780                 }
4781                 // Don't go to high places
4782                 if(groundheight > WATER_LEVEL + 4)
4783                 {
4784                         //infostream<<"-> Underwater"<<std::endl;
4785                         continue;
4786                 }
4787                 
4788                 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4789                 bool is_good = false;
4790                 s32 air_count = 0;
4791                 for(s32 i=0; i<10; i++){
4792                         v3s16 blockpos = getNodeBlockPos(nodepos);
4793                         map.emergeBlock(blockpos, true);
4794                         MapNode n = map.getNodeNoEx(nodepos);
4795                         if(n.getContent() == CONTENT_AIR){
4796                                 air_count++;
4797                                 if(air_count >= 2){
4798                                         is_good = true;
4799                                         nodepos.Y -= 1;
4800                                         break;
4801                                 }
4802                         }
4803                         nodepos.Y++;
4804                 }
4805                 if(is_good){
4806                         // Found a good place
4807                         //infostream<<"Searched through "<<i<<" places."<<std::endl;
4808                         break;
4809                 }
4810         }
4811 #endif
4812         
4813         return intToFloat(nodepos, BS);
4814 }
4815
4816 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4817 {
4818         /*
4819                 Try to get an existing player
4820         */
4821         Player *player = m_env->getPlayer(name);
4822         if(player != NULL)
4823         {
4824                 // If player is already connected, cancel
4825                 if(player->peer_id != 0)
4826                 {
4827                         infostream<<"emergePlayer(): Player already connected"<<std::endl;
4828                         return NULL;
4829                 }
4830
4831                 // Got one.
4832                 player->peer_id = peer_id;
4833                 
4834                 // Reset inventory to creative if in creative mode
4835                 if(g_settings->getBool("creative_mode"))
4836                 {
4837                         // Warning: double code below
4838                         // Backup actual inventory
4839                         player->inventory_backup = new Inventory();
4840                         *(player->inventory_backup) = player->inventory;
4841                         // Set creative inventory
4842                         craft_set_creative_inventory(player, this);
4843                 }
4844
4845                 return player;
4846         }
4847
4848         /*
4849                 If player with the wanted peer_id already exists, cancel.
4850         */
4851         if(m_env->getPlayer(peer_id) != NULL)
4852         {
4853                 infostream<<"emergePlayer(): Player with wrong name but same"
4854                                 " peer_id already exists"<<std::endl;
4855                 return NULL;
4856         }
4857         
4858         /*
4859                 Create a new player
4860         */
4861         {
4862                 // Add authentication stuff
4863                 m_authmanager.add(name);
4864                 m_authmanager.setPassword(name, password);
4865                 m_authmanager.setPrivs(name,
4866                                 stringToPrivs(g_settings->get("default_privs")));
4867
4868                 /* Set player position */
4869                 
4870                 infostream<<"Server: Finding spawn place for player \""
4871                                 <<name<<"\""<<std::endl;
4872
4873                 v3f pos = findSpawnPos(m_env->getServerMap());
4874
4875                 player = new ServerRemotePlayer(m_env, pos, peer_id, name);
4876
4877                 /* Add player to environment */
4878                 m_env->addPlayer(player);
4879
4880                 /* Run scripts */
4881                 ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>(player);
4882                 scriptapi_on_newplayer(m_lua, srp);
4883
4884                 /* Add stuff to inventory */
4885                 if(g_settings->getBool("creative_mode"))
4886                 {
4887                         // Warning: double code above
4888                         // Backup actual inventory
4889                         player->inventory_backup = new Inventory();
4890                         *(player->inventory_backup) = player->inventory;
4891                         // Set creative inventory
4892                         craft_set_creative_inventory(player, this);
4893                 }
4894
4895                 return player;
4896                 
4897         } // create new player
4898 }
4899
4900 void Server::handlePeerChange(PeerChange &c)
4901 {
4902         JMutexAutoLock envlock(m_env_mutex);
4903         JMutexAutoLock conlock(m_con_mutex);
4904         
4905         if(c.type == PEER_ADDED)
4906         {
4907                 /*
4908                         Add
4909                 */
4910
4911                 // Error check
4912                 core::map<u16, RemoteClient*>::Node *n;
4913                 n = m_clients.find(c.peer_id);
4914                 // The client shouldn't already exist
4915                 assert(n == NULL);
4916
4917                 // Create client
4918                 RemoteClient *client = new RemoteClient();
4919                 client->peer_id = c.peer_id;
4920                 m_clients.insert(client->peer_id, client);
4921
4922         } // PEER_ADDED
4923         else if(c.type == PEER_REMOVED)
4924         {
4925                 /*
4926                         Delete
4927                 */
4928
4929                 // Error check
4930                 core::map<u16, RemoteClient*>::Node *n;
4931                 n = m_clients.find(c.peer_id);
4932                 // The client should exist
4933                 assert(n != NULL);
4934                 
4935                 /*
4936                         Mark objects to be not known by the client
4937                 */
4938                 RemoteClient *client = n->getValue();
4939                 // Handle objects
4940                 for(core::map<u16, bool>::Iterator
4941                                 i = client->m_known_objects.getIterator();
4942                                 i.atEnd()==false; i++)
4943                 {
4944                         // Get object
4945                         u16 id = i.getNode()->getKey();
4946                         ServerActiveObject* obj = m_env->getActiveObject(id);
4947                         
4948                         if(obj && obj->m_known_by_count > 0)
4949                                 obj->m_known_by_count--;
4950                 }
4951
4952                 // Collect information about leaving in chat
4953                 std::wstring message;
4954                 {
4955                         Player *player = m_env->getPlayer(c.peer_id);
4956                         if(player != NULL)
4957                         {
4958                                 std::wstring name = narrow_to_wide(player->getName());
4959                                 message += L"*** ";
4960                                 message += name;
4961                                 message += L" left game";
4962                                 if(c.timeout)
4963                                         message += L" (timed out)";
4964                         }
4965                 }
4966
4967                 /*// Delete player
4968                 {
4969                         m_env->removePlayer(c.peer_id);
4970                 }*/
4971
4972                 // Set player client disconnected
4973                 {
4974                         Player *player = m_env->getPlayer(c.peer_id);
4975                         if(player != NULL)
4976                                 player->peer_id = 0;
4977                         
4978                         /*
4979                                 Print out action
4980                         */
4981                         if(player != NULL)
4982                         {
4983                                 std::ostringstream os(std::ios_base::binary);
4984                                 for(core::map<u16, RemoteClient*>::Iterator
4985                                         i = m_clients.getIterator();
4986                                         i.atEnd() == false; i++)
4987                                 {
4988                                         RemoteClient *client = i.getNode()->getValue();
4989                                         assert(client->peer_id == i.getNode()->getKey());
4990                                         if(client->serialization_version == SER_FMT_VER_INVALID)
4991                                                 continue;
4992                                         // Get player
4993                                         Player *player = m_env->getPlayer(client->peer_id);
4994                                         if(!player)
4995                                                 continue;
4996                                         // Get name of player
4997                                         os<<player->getName()<<" ";
4998                                 }
4999
5000                                 actionstream<<player->getName()<<" "
5001                                                 <<(c.timeout?"times out.":"leaves game.")
5002                                                 <<" List of players: "
5003                                                 <<os.str()<<std::endl;
5004                         }
5005                 }
5006                 
5007                 // Delete client
5008                 delete m_clients[c.peer_id];
5009                 m_clients.remove(c.peer_id);
5010
5011                 // Send player info to all remaining clients
5012                 SendPlayerInfos();
5013                 
5014                 // Send leave chat message to all remaining clients
5015                 BroadcastChatMessage(message);
5016                 
5017         } // PEER_REMOVED
5018         else
5019         {
5020                 assert(0);
5021         }
5022 }
5023
5024 void Server::handlePeerChanges()
5025 {
5026         while(m_peer_change_queue.size() > 0)
5027         {
5028                 PeerChange c = m_peer_change_queue.pop_front();
5029
5030                 infostream<<"Server: Handling peer change: "
5031                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5032                                 <<std::endl;
5033
5034                 handlePeerChange(c);
5035         }
5036 }
5037
5038 u64 Server::getPlayerPrivs(Player *player)
5039 {
5040         if(player==NULL)
5041                 return 0;
5042         std::string playername = player->getName();
5043         // Local player gets all privileges regardless of
5044         // what's set on their account.
5045         if(g_settings->get("name") == playername)
5046         {
5047                 return PRIV_ALL;
5048         }
5049         else
5050         {
5051                 return getPlayerAuthPrivs(playername);
5052         }
5053 }
5054
5055 void dedicated_server_loop(Server &server, bool &kill)
5056 {
5057         DSTACK(__FUNCTION_NAME);
5058         
5059         infostream<<DTIME<<std::endl;
5060         infostream<<"========================"<<std::endl;
5061         infostream<<"Running dedicated server"<<std::endl;
5062         infostream<<"========================"<<std::endl;
5063         infostream<<std::endl;
5064
5065         IntervalLimiter m_profiler_interval;
5066
5067         for(;;)
5068         {
5069                 // This is kind of a hack but can be done like this
5070                 // because server.step() is very light
5071                 {
5072                         ScopeProfiler sp(g_profiler, "dedicated server sleep");
5073                         sleep_ms(30);
5074                 }
5075                 server.step(0.030);
5076
5077                 if(server.getShutdownRequested() || kill)
5078                 {
5079                         infostream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
5080                         break;
5081                 }
5082
5083                 /*
5084                         Profiler
5085                 */
5086                 float profiler_print_interval =
5087                                 g_settings->getFloat("profiler_print_interval");
5088                 if(profiler_print_interval != 0)
5089                 {
5090                         if(m_profiler_interval.step(0.030, profiler_print_interval))
5091                         {
5092                                 infostream<<"Profiler:"<<std::endl;
5093                                 g_profiler->print(infostream);
5094                                 g_profiler->clear();
5095                         }
5096                 }
5097                 
5098                 /*
5099                         Player info
5100                 */
5101                 static int counter = 0;
5102                 counter--;
5103                 if(counter <= 0)
5104                 {
5105                         counter = 10;
5106
5107                         core::list<PlayerInfo> list = server.getPlayerInfo();
5108                         core::list<PlayerInfo>::Iterator i;
5109                         static u32 sum_old = 0;
5110                         u32 sum = PIChecksum(list);
5111                         if(sum != sum_old)
5112                         {
5113                                 infostream<<DTIME<<"Player info:"<<std::endl;
5114                                 for(i=list.begin(); i!=list.end(); i++)
5115                                 {
5116                                         i->PrintLine(&infostream);
5117                                 }
5118                         }
5119                         sum_old = sum;
5120                 }
5121         }
5122 }
5123
5124