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