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