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