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