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