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