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