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