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