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