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