]> git.lizzy.rs Git - minetest.git/blob - src/server.cpp
Scripting WIP
[minetest.git] / src / server.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
14
15 You should have received a copy of the GNU 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 "utility.h"
22 #include <iostream>
23 #include "clientserver.h"
24 #include "map.h"
25 #include "jmutexautolock.h"
26 #include "main.h"
27 #include "constants.h"
28 #include "voxel.h"
29 #include "materials.h"
30 #include "mineral.h"
31 #include "config.h"
32 #include "servercommand.h"
33 #include "filesys.h"
34 #include "content_mapnode.h"
35 #include "content_craft.h"
36 #include "content_nodemeta.h"
37 #include "mapblock.h"
38 #include "serverobject.h"
39 #include "settings.h"
40 #include "profiler.h"
41 #include "log.h"
42 #include "script.h"
43 #include "scriptapi.h"
44
45 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
46
47 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
48
49 class MapEditEventIgnorer
50 {
51 public:
52         MapEditEventIgnorer(bool *flag):
53                 m_flag(flag)
54         {
55                 if(*m_flag == false)
56                         *m_flag = true;
57                 else
58                         m_flag = NULL;
59         }
60
61         ~MapEditEventIgnorer()
62         {
63                 if(m_flag)
64                 {
65                         assert(*m_flag);
66                         *m_flag = false;
67                 }
68         }
69         
70 private:
71         bool *m_flag;
72 };
73
74 void * ServerThread::Thread()
75 {
76         ThreadStarted();
77
78         log_register_thread("ServerThread");
79
80         DSTACK(__FUNCTION_NAME);
81
82         BEGIN_DEBUG_EXCEPTION_HANDLER
83
84         while(getRun())
85         {
86                 try{
87                         //TimeTaker timer("AsyncRunStep() + Receive()");
88
89                         {
90                                 //TimeTaker timer("AsyncRunStep()");
91                                 m_server->AsyncRunStep();
92                         }
93                 
94                         //infostream<<"Running m_server->Receive()"<<std::endl;
95                         m_server->Receive();
96                 }
97                 catch(con::NoIncomingDataException &e)
98                 {
99                 }
100                 catch(con::PeerNotFoundException &e)
101                 {
102                         infostream<<"Server: PeerNotFoundException"<<std::endl;
103                 }
104         }
105         
106         END_DEBUG_EXCEPTION_HANDLER(errorstream)
107
108         return NULL;
109 }
110
111 void * EmergeThread::Thread()
112 {
113         ThreadStarted();
114
115         log_register_thread("EmergeThread");
116
117         DSTACK(__FUNCTION_NAME);
118
119         BEGIN_DEBUG_EXCEPTION_HANDLER
120
121         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
122         
123         /*
124                 Get block info from queue, emerge them and send them
125                 to clients.
126
127                 After queue is empty, exit.
128         */
129         while(getRun())
130         {
131                 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
132                 if(qptr == NULL)
133                         break;
134                 
135                 SharedPtr<QueuedBlockEmerge> q(qptr);
136
137                 v3s16 &p = q->pos;
138                 v2s16 p2d(p.X,p.Z);
139
140                 /*
141                         Do not generate over-limit
142                 */
143                 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
144                 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
145                 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
146                 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
147                 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
148                 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
149                         continue;
150                         
151                 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
152
153                 //TimeTaker timer("block emerge");
154                 
155                 /*
156                         Try to emerge it from somewhere.
157
158                         If it is only wanted as optional, only loading from disk
159                         will be allowed.
160                 */
161                 
162                 /*
163                         Check if any peer wants it as non-optional. In that case it
164                         will be generated.
165
166                         Also decrement the emerge queue count in clients.
167                 */
168
169                 bool only_from_disk = true;
170
171                 {
172                         core::map<u16, u8>::Iterator i;
173                         for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
174                         {
175                                 //u16 peer_id = i.getNode()->getKey();
176
177                                 // Check flags
178                                 u8 flags = i.getNode()->getValue();
179                                 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
180                                         only_from_disk = false;
181                                 
182                         }
183                 }
184                 
185                 if(enable_mapgen_debug_info)
186                         infostream<<"EmergeThread: p="
187                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
188                                         <<"only_from_disk="<<only_from_disk<<std::endl;
189                 
190                 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
191                         
192                 //core::map<v3s16, MapBlock*> changed_blocks;
193                 //core::map<v3s16, MapBlock*> lighting_invalidated_blocks;
194
195                 MapBlock *block = NULL;
196                 bool got_block = true;
197                 core::map<v3s16, MapBlock*> modified_blocks;
198                 
199                 /*
200                         Fetch block from map or generate a single block
201                 */
202                 {
203                         JMutexAutoLock envlock(m_server->m_env_mutex);
204                         
205                         // Load sector if it isn't loaded
206                         if(map.getSectorNoGenerateNoEx(p2d) == NULL)
207                                 //map.loadSectorFull(p2d);
208                                 map.loadSectorMeta(p2d);
209
210                         block = map.getBlockNoCreateNoEx(p);
211                         if(!block || block->isDummy() || !block->isGenerated())
212                         {
213                                 if(enable_mapgen_debug_info)
214                                         infostream<<"EmergeThread: not in memory, loading"<<std::endl;
215
216                                 // Get, load or create sector
217                                 /*ServerMapSector *sector =
218                                                 (ServerMapSector*)map.createSector(p2d);*/
219
220                                 // Load/generate block
221
222                                 /*block = map.emergeBlock(p, sector, changed_blocks,
223                                                 lighting_invalidated_blocks);*/
224
225                                 block = map.loadBlock(p);
226                                 
227                                 if(only_from_disk == false)
228                                 {
229                                         if(block == NULL || block->isGenerated() == false)
230                                         {
231                                                 if(enable_mapgen_debug_info)
232                                                         infostream<<"EmergeThread: generating"<<std::endl;
233                                                 block = map.generateBlock(p, modified_blocks);
234                                         }
235                                 }
236
237                                 if(enable_mapgen_debug_info)
238                                         infostream<<"EmergeThread: ended up with: "
239                                                         <<analyze_block(block)<<std::endl;
240
241                                 if(block == NULL)
242                                 {
243                                         got_block = false;
244                                 }
245                                 else
246                                 {
247                                         /*
248                                                 Ignore map edit events, they will not need to be
249                                                 sent to anybody because the block hasn't been sent
250                                                 to anybody
251                                         */
252                                         MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
253                                         
254                                         // Activate objects and stuff
255                                         m_server->m_env->activateBlock(block, 3600);
256                                 }
257                         }
258                         else
259                         {
260                                 /*if(block->getLightingExpired()){
261                                         lighting_invalidated_blocks[block->getPos()] = block;
262                                 }*/
263                         }
264
265                         // TODO: Some additional checking and lighting updating,
266                         //       see emergeBlock
267                 }
268
269                 {//envlock
270                 JMutexAutoLock envlock(m_server->m_env_mutex);
271                 
272                 if(got_block)
273                 {
274                         /*
275                                 Collect a list of blocks that have been modified in
276                                 addition to the fetched one.
277                         */
278
279 #if 0
280                         if(lighting_invalidated_blocks.size() > 0)
281                         {
282                                 /*infostream<<"lighting "<<lighting_invalidated_blocks.size()
283                                                 <<" blocks"<<std::endl;*/
284                         
285                                 // 50-100ms for single block generation
286                                 //TimeTaker timer("** EmergeThread updateLighting");
287                                 
288                                 // Update lighting without locking the environment mutex,
289                                 // add modified blocks to changed blocks
290                                 map.updateLighting(lighting_invalidated_blocks, modified_blocks);
291                         }
292                                 
293                         // Add all from changed_blocks to modified_blocks
294                         for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
295                                         i.atEnd() == false; i++)
296                         {
297                                 MapBlock *block = i.getNode()->getValue();
298                                 modified_blocks.insert(block->getPos(), block);
299                         }
300 #endif
301                 }
302                 // If we got no block, there should be no invalidated blocks
303                 else
304                 {
305                         //assert(lighting_invalidated_blocks.size() == 0);
306                 }
307
308                 }//envlock
309
310                 /*
311                         Set sent status of modified blocks on clients
312                 */
313         
314                 // NOTE: Server's clients are also behind the connection mutex
315                 JMutexAutoLock lock(m_server->m_con_mutex);
316
317                 /*
318                         Add the originally fetched block to the modified list
319                 */
320                 if(got_block)
321                 {
322                         modified_blocks.insert(p, block);
323                 }
324                 
325                 /*
326                         Set the modified blocks unsent for all the clients
327                 */
328                 
329                 for(core::map<u16, RemoteClient*>::Iterator
330                                 i = m_server->m_clients.getIterator();
331                                 i.atEnd() == false; i++)
332                 {
333                         RemoteClient *client = i.getNode()->getValue();
334                         
335                         if(modified_blocks.size() > 0)
336                         {
337                                 // Remove block from sent history
338                                 client->SetBlocksNotSent(modified_blocks);
339                         }
340                 }
341                 
342         }
343
344         END_DEBUG_EXCEPTION_HANDLER(errorstream)
345
346         return NULL;
347 }
348
349 void RemoteClient::GetNextBlocks(Server *server, float dtime,
350                 core::array<PrioritySortedBlockTransfer> &dest)
351 {
352         DSTACK(__FUNCTION_NAME);
353         
354         /*u32 timer_result;
355         TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
356         
357         // Increment timers
358         m_nothing_to_send_pause_timer -= dtime;
359         m_nearest_unsent_reset_timer += dtime;
360         
361         if(m_nothing_to_send_pause_timer >= 0)
362         {
363                 return;
364         }
365
366         // Won't send anything if already sending
367         if(m_blocks_sending.size() >= g_settings->getU16
368                         ("max_simultaneous_block_sends_per_client"))
369         {
370                 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
371                 return;
372         }
373
374         //TimeTaker timer("RemoteClient::GetNextBlocks");
375         
376         Player *player = server->m_env->getPlayer(peer_id);
377
378         assert(player != NULL);
379
380         v3f playerpos = player->getPosition();
381         v3f playerspeed = player->getSpeed();
382         v3f playerspeeddir(0,0,0);
383         if(playerspeed.getLength() > 1.0*BS)
384                 playerspeeddir = playerspeed / playerspeed.getLength();
385         // Predict to next block
386         v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
387
388         v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
389
390         v3s16 center = getNodeBlockPos(center_nodepos);
391         
392         // Camera position and direction
393         v3f camera_pos = player->getEyePosition();
394         v3f camera_dir = v3f(0,0,1);
395         camera_dir.rotateYZBy(player->getPitch());
396         camera_dir.rotateXZBy(player->getYaw());
397
398         /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
399                         <<camera_dir.Z<<")"<<std::endl;*/
400
401         /*
402                 Get the starting value of the block finder radius.
403         */
404                 
405         if(m_last_center != center)
406         {
407                 m_nearest_unsent_d = 0;
408                 m_last_center = center;
409         }
410
411         /*infostream<<"m_nearest_unsent_reset_timer="
412                         <<m_nearest_unsent_reset_timer<<std::endl;*/
413                         
414         // Reset periodically to workaround for some bugs or stuff
415         if(m_nearest_unsent_reset_timer > 20.0)
416         {
417                 m_nearest_unsent_reset_timer = 0;
418                 m_nearest_unsent_d = 0;
419                 //infostream<<"Resetting m_nearest_unsent_d for "
420                 //              <<server->getPlayerName(peer_id)<<std::endl;
421         }
422
423         //s16 last_nearest_unsent_d = m_nearest_unsent_d;
424         s16 d_start = m_nearest_unsent_d;
425
426         //infostream<<"d_start="<<d_start<<std::endl;
427
428         u16 max_simul_sends_setting = g_settings->getU16
429                         ("max_simultaneous_block_sends_per_client");
430         u16 max_simul_sends_usually = max_simul_sends_setting;
431
432         /*
433                 Check the time from last addNode/removeNode.
434                 
435                 Decrease send rate if player is building stuff.
436         */
437         m_time_from_building += dtime;
438         if(m_time_from_building < g_settings->getFloat(
439                                 "full_block_send_enable_min_time_from_building"))
440         {
441                 max_simul_sends_usually
442                         = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
443         }
444         
445         /*
446                 Number of blocks sending + number of blocks selected for sending
447         */
448         u32 num_blocks_selected = m_blocks_sending.size();
449         
450         /*
451                 next time d will be continued from the d from which the nearest
452                 unsent block was found this time.
453
454                 This is because not necessarily any of the blocks found this
455                 time are actually sent.
456         */
457         s32 new_nearest_unsent_d = -1;
458
459         s16 d_max = g_settings->getS16("max_block_send_distance");
460         s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
461         
462         // Don't loop very much at a time
463         s16 max_d_increment_at_time = 2;
464         if(d_max > d_start + max_d_increment_at_time)
465                 d_max = d_start + max_d_increment_at_time;
466         /*if(d_max_gen > d_start+2)
467                 d_max_gen = d_start+2;*/
468         
469         //infostream<<"Starting from "<<d_start<<std::endl;
470
471         s32 nearest_emerged_d = -1;
472         s32 nearest_emergefull_d = -1;
473         s32 nearest_sent_d = -1;
474         bool queue_is_full = false;
475         
476         s16 d;
477         for(d = d_start; d <= d_max; d++)
478         {
479                 /*errorstream<<"checking d="<<d<<" for "
480                                 <<server->getPlayerName(peer_id)<<std::endl;*/
481                 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
482                 
483                 /*
484                         If m_nearest_unsent_d was changed by the EmergeThread
485                         (it can change it to 0 through SetBlockNotSent),
486                         update our d to it.
487                         Else update m_nearest_unsent_d
488                 */
489                 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
490                 {
491                         d = m_nearest_unsent_d;
492                         last_nearest_unsent_d = m_nearest_unsent_d;
493                 }*/
494
495                 /*
496                         Get the border/face dot coordinates of a "d-radiused"
497                         box
498                 */
499                 core::list<v3s16> list;
500                 getFacePositions(list, d);
501                 
502                 core::list<v3s16>::Iterator li;
503                 for(li=list.begin(); li!=list.end(); li++)
504                 {
505                         v3s16 p = *li + center;
506                         
507                         /*
508                                 Send throttling
509                                 - Don't allow too many simultaneous transfers
510                                 - EXCEPT when the blocks are very close
511
512                                 Also, don't send blocks that are already flying.
513                         */
514                         
515                         // Start with the usual maximum
516                         u16 max_simul_dynamic = max_simul_sends_usually;
517                         
518                         // If block is very close, allow full maximum
519                         if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
520                                 max_simul_dynamic = max_simul_sends_setting;
521
522                         // Don't select too many blocks for sending
523                         if(num_blocks_selected >= max_simul_dynamic)
524                         {
525                                 queue_is_full = true;
526                                 goto queue_full_break;
527                         }
528                         
529                         // Don't send blocks that are currently being transferred
530                         if(m_blocks_sending.find(p) != NULL)
531                                 continue;
532                 
533                         /*
534                                 Do not go over-limit
535                         */
536                         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
537                         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
538                         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
539                         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
540                         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
541                         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
542                                 continue;
543                 
544                         // If this is true, inexistent block will be made from scratch
545                         bool generate = d <= d_max_gen;
546                         
547                         {
548                                 /*// Limit the generating area vertically to 2/3
549                                 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
550                                         generate = false;*/
551
552                                 // Limit the send area vertically to 1/2
553                                 if(abs(p.Y - center.Y) > d_max / 2)
554                                         continue;
555                         }
556
557 #if 0
558                         /*
559                                 If block is far away, don't generate it unless it is
560                                 near ground level.
561                         */
562                         if(d >= 4)
563                         {
564         #if 1
565                                 // Block center y in nodes
566                                 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
567                                 // Don't generate if it's very high or very low
568                                 if(y < -64 || y > 64)
569                                         generate = false;
570         #endif
571         #if 0
572                                 v2s16 p2d_nodes_center(
573                                         MAP_BLOCKSIZE*p.X,
574                                         MAP_BLOCKSIZE*p.Z);
575                                 
576                                 // Get ground height in nodes
577                                 s16 gh = server->m_env->getServerMap().findGroundLevel(
578                                                 p2d_nodes_center);
579
580                                 // If differs a lot, don't generate
581                                 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
582                                         generate = false;
583                                         // Actually, don't even send it
584                                         //continue;
585         #endif
586                         }
587 #endif
588
589                         //infostream<<"d="<<d<<std::endl;
590 #if 1
591                         /*
592                                 Don't generate or send if not in sight
593                                 FIXME This only works if the client uses a small enough
594                                 FOV setting. The default of 72 degrees is fine.
595                         */
596
597                         float camera_fov = (72.0*PI/180) * 4./3.;
598                         if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
599                         {
600                                 continue;
601                         }
602 #endif
603                         /*
604                                 Don't send already sent blocks
605                         */
606                         {
607                                 if(m_blocks_sent.find(p) != NULL)
608                                 {
609                                         continue;
610                                 }
611                         }
612
613                         /*
614                                 Check if map has this block
615                         */
616                         MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
617                         
618                         bool surely_not_found_on_disk = false;
619                         bool block_is_invalid = false;
620                         if(block != NULL)
621                         {
622                                 // Reset usage timer, this block will be of use in the future.
623                                 block->resetUsageTimer();
624
625                                 // Block is dummy if data doesn't exist.
626                                 // It means it has been not found from disk and not generated
627                                 if(block->isDummy())
628                                 {
629                                         surely_not_found_on_disk = true;
630                                 }
631                                 
632                                 // Block is valid if lighting is up-to-date and data exists
633                                 if(block->isValid() == false)
634                                 {
635                                         block_is_invalid = true;
636                                 }
637                                 
638                                 /*if(block->isFullyGenerated() == false)
639                                 {
640                                         block_is_invalid = true;
641                                 }*/
642
643 #if 0
644                                 v2s16 p2d(p.X, p.Z);
645                                 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
646                                 v2s16 chunkpos = map->sector_to_chunk(p2d);
647                                 if(map->chunkNonVolatile(chunkpos) == false)
648                                         block_is_invalid = true;
649 #endif
650                                 if(block->isGenerated() == false)
651                                         block_is_invalid = true;
652 #if 1
653                                 /*
654                                         If block is not close, don't send it unless it is near
655                                         ground level.
656
657                                         Block is near ground level if night-time mesh
658                                         differs from day-time mesh.
659                                 */
660                                 if(d >= 4)
661                                 {
662                                         if(block->dayNightDiffed() == false)
663                                                 continue;
664                                 }
665 #endif
666                         }
667
668                         /*
669                                 If block has been marked to not exist on disk (dummy)
670                                 and generating new ones is not wanted, skip block.
671                         */
672                         if(generate == false && surely_not_found_on_disk == true)
673                         {
674                                 // get next one.
675                                 continue;
676                         }
677
678                         /*
679                                 Add inexistent block to emerge queue.
680                         */
681                         if(block == NULL || surely_not_found_on_disk || block_is_invalid)
682                         {
683                                 //TODO: Get value from somewhere
684                                 // Allow only one block in emerge queue
685                                 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
686                                 // Allow two blocks in queue per client
687                                 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
688                                 if(server->m_emerge_queue.peerItemCount(peer_id) < 25)
689                                 {
690                                         //infostream<<"Adding block to emerge queue"<<std::endl;
691                                         
692                                         // Add it to the emerge queue and trigger the thread
693                                         
694                                         u8 flags = 0;
695                                         if(generate == false)
696                                                 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
697                                         
698                                         server->m_emerge_queue.addBlock(peer_id, p, flags);
699                                         server->m_emergethread.trigger();
700
701                                         if(nearest_emerged_d == -1)
702                                                 nearest_emerged_d = d;
703                                 } else {
704                                         if(nearest_emergefull_d == -1)
705                                                 nearest_emergefull_d = d;
706                                 }
707                                 
708                                 // get next one.
709                                 continue;
710                         }
711
712                         if(nearest_sent_d == -1)
713                                 nearest_sent_d = d;
714
715                         /*
716                                 Add block to send queue
717                         */
718
719                         /*errorstream<<"sending from d="<<d<<" to "
720                                         <<server->getPlayerName(peer_id)<<std::endl;*/
721
722                         PrioritySortedBlockTransfer q((float)d, p, peer_id);
723
724                         dest.push_back(q);
725
726                         num_blocks_selected += 1;
727                 }
728         }
729 queue_full_break:
730
731         //infostream<<"Stopped at "<<d<<std::endl;
732         
733         // If nothing was found for sending and nothing was queued for
734         // emerging, continue next time browsing from here
735         if(nearest_emerged_d != -1){
736                 new_nearest_unsent_d = nearest_emerged_d;
737         } else if(nearest_emergefull_d != -1){
738                 new_nearest_unsent_d = nearest_emergefull_d;
739         } else {
740                 if(d > g_settings->getS16("max_block_send_distance")){
741                         new_nearest_unsent_d = 0;
742                         m_nothing_to_send_pause_timer = 2.0;
743                         /*infostream<<"GetNextBlocks(): d wrapped around for "
744                                         <<server->getPlayerName(peer_id)
745                                         <<"; setting to 0 and pausing"<<std::endl;*/
746                 } else {
747                         if(nearest_sent_d != -1)
748                                 new_nearest_unsent_d = nearest_sent_d;
749                         else
750                                 new_nearest_unsent_d = d;
751                 }
752         }
753
754         if(new_nearest_unsent_d != -1)
755                 m_nearest_unsent_d = new_nearest_unsent_d;
756
757         /*timer_result = timer.stop(true);
758         if(timer_result != 0)
759                 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
760 }
761
762 void RemoteClient::SendObjectData(
763                 Server *server,
764                 float dtime,
765                 core::map<v3s16, bool> &stepped_blocks
766         )
767 {
768         DSTACK(__FUNCTION_NAME);
769
770         // Can't send anything without knowing version
771         if(serialization_version == SER_FMT_VER_INVALID)
772         {
773                 infostream<<"RemoteClient::SendObjectData(): Not sending, no version."
774                                 <<std::endl;
775                 return;
776         }
777
778         /*
779                 Send a TOCLIENT_OBJECTDATA packet.
780                 Sent as unreliable.
781
782                 u16 command
783                 u16 number of player positions
784                 for each player:
785                         u16 peer_id
786                         v3s32 position*100
787                         v3s32 speed*100
788                         s32 pitch*100
789                         s32 yaw*100
790                 u16 count of blocks
791                 for each block:
792                         block objects
793         */
794
795         std::ostringstream os(std::ios_base::binary);
796         u8 buf[12];
797         
798         // Write command
799         writeU16(buf, TOCLIENT_OBJECTDATA);
800         os.write((char*)buf, 2);
801         
802         /*
803                 Get and write player data
804         */
805         
806         // Get connected players
807         core::list<Player*> players = server->m_env->getPlayers(true);
808
809         // Write player count
810         u16 playercount = players.size();
811         writeU16(buf, playercount);
812         os.write((char*)buf, 2);
813
814         core::list<Player*>::Iterator i;
815         for(i = players.begin();
816                         i != players.end(); i++)
817         {
818                 Player *player = *i;
819
820                 v3f pf = player->getPosition();
821                 v3f sf = player->getSpeed();
822
823                 v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
824                 v3s32 speed_i   (sf.X*100, sf.Y*100, sf.Z*100);
825                 s32   pitch_i   (player->getPitch() * 100);
826                 s32   yaw_i     (player->getYaw() * 100);
827                 
828                 writeU16(buf, player->peer_id);
829                 os.write((char*)buf, 2);
830                 writeV3S32(buf, position_i);
831                 os.write((char*)buf, 12);
832                 writeV3S32(buf, speed_i);
833                 os.write((char*)buf, 12);
834                 writeS32(buf, pitch_i);
835                 os.write((char*)buf, 4);
836                 writeS32(buf, yaw_i);
837                 os.write((char*)buf, 4);
838         }
839         
840         /*
841                 Get and write object data (dummy, for compatibility)
842         */
843
844         // Write block count
845         writeU16(buf, 0);
846         os.write((char*)buf, 2);
847
848         /*
849                 Send data
850         */
851         
852         //infostream<<"Server: Sending object data to "<<peer_id<<std::endl;
853
854         // Make data buffer
855         std::string s = os.str();
856         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
857         // Send as unreliable
858         server->m_con.Send(peer_id, 0, data, false);
859 }
860
861 void RemoteClient::GotBlock(v3s16 p)
862 {
863         if(m_blocks_sending.find(p) != NULL)
864                 m_blocks_sending.remove(p);
865         else
866         {
867                 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
868                                 " m_blocks_sending"<<std::endl;*/
869                 m_excess_gotblocks++;
870         }
871         m_blocks_sent.insert(p, true);
872 }
873
874 void RemoteClient::SentBlock(v3s16 p)
875 {
876         if(m_blocks_sending.find(p) == NULL)
877                 m_blocks_sending.insert(p, 0.0);
878         else
879                 infostream<<"RemoteClient::SentBlock(): Sent block"
880                                 " already in m_blocks_sending"<<std::endl;
881 }
882
883 void RemoteClient::SetBlockNotSent(v3s16 p)
884 {
885         m_nearest_unsent_d = 0;
886         
887         if(m_blocks_sending.find(p) != NULL)
888                 m_blocks_sending.remove(p);
889         if(m_blocks_sent.find(p) != NULL)
890                 m_blocks_sent.remove(p);
891 }
892
893 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
894 {
895         m_nearest_unsent_d = 0;
896         
897         for(core::map<v3s16, MapBlock*>::Iterator
898                         i = blocks.getIterator();
899                         i.atEnd()==false; i++)
900         {
901                 v3s16 p = i.getNode()->getKey();
902
903                 if(m_blocks_sending.find(p) != NULL)
904                         m_blocks_sending.remove(p);
905                 if(m_blocks_sent.find(p) != NULL)
906                         m_blocks_sent.remove(p);
907         }
908 }
909
910 /*
911         PlayerInfo
912 */
913
914 PlayerInfo::PlayerInfo()
915 {
916         name[0] = 0;
917         avg_rtt = 0;
918 }
919
920 void PlayerInfo::PrintLine(std::ostream *s)
921 {
922         (*s)<<id<<": ";
923         (*s)<<"\""<<name<<"\" ("
924                         <<(position.X/10)<<","<<(position.Y/10)
925                         <<","<<(position.Z/10)<<") ";
926         address.print(s);
927         (*s)<<" avg_rtt="<<avg_rtt;
928         (*s)<<std::endl;
929 }
930
931 u32 PIChecksum(core::list<PlayerInfo> &l)
932 {
933         core::list<PlayerInfo>::Iterator i;
934         u32 checksum = 1;
935         u32 a = 10;
936         for(i=l.begin(); i!=l.end(); i++)
937         {
938                 checksum += a * (i->id+1);
939                 checksum ^= 0x435aafcd;
940                 a *= 10;
941         }
942         return checksum;
943 }
944
945 /*
946         Server
947 */
948
949 Server::Server(
950                 std::string mapsavedir,
951                 std::string configpath
952         ):
953         m_env(NULL),
954         m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
955         m_authmanager(mapsavedir+DIR_DELIM+"auth.txt"),
956         m_banmanager(mapsavedir+DIR_DELIM+"ipban.txt"),
957         m_lua(NULL),
958         //m_scriptapi(NULL),
959         m_thread(this),
960         m_emergethread(this),
961         m_time_counter(0),
962         m_time_of_day_send_timer(0),
963         m_uptime(0),
964         m_mapsavedir(mapsavedir),
965         m_configpath(configpath),
966         m_shutdown_requested(false),
967         m_ignore_map_edit_events(false),
968         m_ignore_map_edit_events_peer_id(0)
969 {
970         m_liquid_transform_timer = 0.0;
971         m_print_info_timer = 0.0;
972         m_objectdata_timer = 0.0;
973         m_emergethread_trigger_timer = 0.0;
974         m_savemap_timer = 0.0;
975         
976         m_env_mutex.Init();
977         m_con_mutex.Init();
978         m_step_dtime_mutex.Init();
979         m_step_dtime = 0.0;
980
981         JMutexAutoLock envlock(m_env_mutex);
982         JMutexAutoLock conlock(m_con_mutex);
983         
984         // Initialize scripting
985         
986         infostream<<"Server: Initializing scripting"<<std::endl;
987         m_lua = script_init();
988         assert(m_lua);
989         // Export API
990         scriptapi_export(m_lua, this);
991         // Load and run scripts
992         std::string defaultscript = porting::path_data + DIR_DELIM
993                         + "scripts" + DIR_DELIM + "default.lua";
994         bool success = script_load(m_lua, defaultscript.c_str());
995         if(!success){
996                 errorstream<<"Server: Failed to load and run "
997                                 <<defaultscript<<std::endl;
998                 assert(0);
999         }
1000         
1001         // Initialize Environment
1002         
1003         m_env = new ServerEnvironment(new ServerMap(mapsavedir), m_lua);
1004
1005         // Give environment reference to scripting api
1006         scriptapi_add_environment(m_lua, m_env);
1007         
1008         // Register us to receive map edit events
1009         m_env->getMap().addEventReceiver(this);
1010
1011         // If file exists, load environment metadata
1012         if(fs::PathExists(m_mapsavedir+DIR_DELIM+"env_meta.txt"))
1013         {
1014                 infostream<<"Server: Loading environment metadata"<<std::endl;
1015                 m_env->loadMeta(m_mapsavedir);
1016         }
1017
1018         // Load players
1019         infostream<<"Server: Loading players"<<std::endl;
1020         m_env->deSerializePlayers(m_mapsavedir);
1021 }
1022
1023 Server::~Server()
1024 {
1025         infostream<<"Server::~Server()"<<std::endl;
1026
1027         /*
1028                 Send shutdown message
1029         */
1030         {
1031                 JMutexAutoLock conlock(m_con_mutex);
1032                 
1033                 std::wstring line = L"*** Server shutting down";
1034
1035                 /*
1036                         Send the message to clients
1037                 */
1038                 for(core::map<u16, RemoteClient*>::Iterator
1039                         i = m_clients.getIterator();
1040                         i.atEnd() == false; i++)
1041                 {
1042                         // Get client and check that it is valid
1043                         RemoteClient *client = i.getNode()->getValue();
1044                         assert(client->peer_id == i.getNode()->getKey());
1045                         if(client->serialization_version == SER_FMT_VER_INVALID)
1046                                 continue;
1047
1048                         try{
1049                                 SendChatMessage(client->peer_id, line);
1050                         }
1051                         catch(con::PeerNotFoundException &e)
1052                         {}
1053                 }
1054         }
1055         
1056         {
1057                 JMutexAutoLock envlock(m_env_mutex);
1058
1059                 /*
1060                         Save players
1061                 */
1062                 infostream<<"Server: Saving players"<<std::endl;
1063                 m_env->serializePlayers(m_mapsavedir);
1064
1065                 /*
1066                         Save environment metadata
1067                 */
1068                 infostream<<"Server: Saving environment metadata"<<std::endl;
1069                 m_env->saveMeta(m_mapsavedir);
1070         }
1071                 
1072         /*
1073                 Stop threads
1074         */
1075         stop();
1076         
1077         /*
1078                 Delete clients
1079         */
1080         {
1081                 JMutexAutoLock clientslock(m_con_mutex);
1082
1083                 for(core::map<u16, RemoteClient*>::Iterator
1084                         i = m_clients.getIterator();
1085                         i.atEnd() == false; i++)
1086                 {
1087                         /*// Delete player
1088                         // NOTE: These are removed by env destructor
1089                         {
1090                                 u16 peer_id = i.getNode()->getKey();
1091                                 JMutexAutoLock envlock(m_env_mutex);
1092                                 m_env->removePlayer(peer_id);
1093                         }*/
1094                         
1095                         // Delete client
1096                         delete i.getNode()->getValue();
1097                 }
1098         }
1099
1100         // Delete Environment
1101         delete m_env;
1102         
1103         // Deinitialize scripting
1104         infostream<<"Server: Deinitializing scripting"<<std::endl;
1105         script_deinit(m_lua);
1106 }
1107
1108 void Server::start(unsigned short port)
1109 {
1110         DSTACK(__FUNCTION_NAME);
1111         // Stop thread if already running
1112         m_thread.stop();
1113         
1114         // Initialize connection
1115         m_con.SetTimeoutMs(30);
1116         m_con.Serve(port);
1117
1118         // Start thread
1119         m_thread.setRun(true);
1120         m_thread.Start();
1121         
1122         infostream<<"Server: Started on port "<<port<<std::endl;
1123 }
1124
1125 void Server::stop()
1126 {
1127         DSTACK(__FUNCTION_NAME);
1128         
1129         infostream<<"Server: Stopping and waiting threads"<<std::endl;
1130
1131         // Stop threads (set run=false first so both start stopping)
1132         m_thread.setRun(false);
1133         m_emergethread.setRun(false);
1134         m_thread.stop();
1135         m_emergethread.stop();
1136         
1137         infostream<<"Server: Threads stopped"<<std::endl;
1138 }
1139
1140 void Server::step(float dtime)
1141 {
1142         DSTACK(__FUNCTION_NAME);
1143         // Limit a bit
1144         if(dtime > 2.0)
1145                 dtime = 2.0;
1146         {
1147                 JMutexAutoLock lock(m_step_dtime_mutex);
1148                 m_step_dtime += dtime;
1149         }
1150 }
1151
1152 void Server::AsyncRunStep()
1153 {
1154         DSTACK(__FUNCTION_NAME);
1155         
1156         g_profiler->add("Server::AsyncRunStep (num)", 1);
1157         
1158         float dtime;
1159         {
1160                 JMutexAutoLock lock1(m_step_dtime_mutex);
1161                 dtime = m_step_dtime;
1162         }
1163         
1164         {
1165                 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
1166                 // Send blocks to clients
1167                 SendBlocks(dtime);
1168         }
1169         
1170         if(dtime < 0.001)
1171                 return;
1172         
1173         g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1174
1175         //infostream<<"Server steps "<<dtime<<std::endl;
1176         //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1177         
1178         {
1179                 JMutexAutoLock lock1(m_step_dtime_mutex);
1180                 m_step_dtime -= dtime;
1181         }
1182
1183         /*
1184                 Update uptime
1185         */
1186         {
1187                 m_uptime.set(m_uptime.get() + dtime);
1188         }
1189         
1190         {
1191                 // Process connection's timeouts
1192                 JMutexAutoLock lock2(m_con_mutex);
1193                 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1194                 m_con.RunTimeouts(dtime);
1195         }
1196         
1197         {
1198                 // This has to be called so that the client list gets synced
1199                 // with the peer list of the connection
1200                 handlePeerChanges();
1201         }
1202
1203         /*
1204                 Update m_time_of_day and overall game time
1205         */
1206         {
1207                 JMutexAutoLock envlock(m_env_mutex);
1208
1209                 m_time_counter += dtime;
1210                 f32 speed = g_settings->getFloat("time_speed") * 24000./(24.*3600);
1211                 u32 units = (u32)(m_time_counter*speed);
1212                 m_time_counter -= (f32)units / speed;
1213                 
1214                 m_env->setTimeOfDay((m_env->getTimeOfDay() + units) % 24000);
1215                 
1216                 //infostream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1217
1218                 /*
1219                         Send to clients at constant intervals
1220                 */
1221
1222                 m_time_of_day_send_timer -= dtime;
1223                 if(m_time_of_day_send_timer < 0.0)
1224                 {
1225                         m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1226
1227                         //JMutexAutoLock envlock(m_env_mutex);
1228                         JMutexAutoLock conlock(m_con_mutex);
1229
1230                         for(core::map<u16, RemoteClient*>::Iterator
1231                                 i = m_clients.getIterator();
1232                                 i.atEnd() == false; i++)
1233                         {
1234                                 RemoteClient *client = i.getNode()->getValue();
1235                                 //Player *player = m_env->getPlayer(client->peer_id);
1236                                 
1237                                 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1238                                                 m_env->getTimeOfDay());
1239                                 // Send as reliable
1240                                 m_con.Send(client->peer_id, 0, data, true);
1241                         }
1242                 }
1243         }
1244
1245         {
1246                 JMutexAutoLock lock(m_env_mutex);
1247                 // Step environment
1248                 ScopeProfiler sp(g_profiler, "SEnv step");
1249                 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1250                 m_env->step(dtime);
1251         }
1252                 
1253         const float map_timer_and_unload_dtime = 5.15;
1254         if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1255         {
1256                 JMutexAutoLock lock(m_env_mutex);
1257                 // Run Map's timers and unload unused data
1258                 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1259                 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1260                                 g_settings->getFloat("server_unload_unused_data_timeout"));
1261         }
1262         
1263         /*
1264                 Do background stuff
1265         */
1266         
1267         /*
1268                 Transform liquids
1269         */
1270         m_liquid_transform_timer += dtime;
1271         if(m_liquid_transform_timer >= 1.00)
1272         {
1273                 m_liquid_transform_timer -= 1.00;
1274                 
1275                 JMutexAutoLock lock(m_env_mutex);
1276
1277                 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1278
1279                 core::map<v3s16, MapBlock*> modified_blocks;
1280                 m_env->getMap().transformLiquids(modified_blocks);
1281 #if 0           
1282                 /*
1283                         Update lighting
1284                 */
1285                 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1286                 ServerMap &map = ((ServerMap&)m_env->getMap());
1287                 map.updateLighting(modified_blocks, lighting_modified_blocks);
1288                 
1289                 // Add blocks modified by lighting to modified_blocks
1290                 for(core::map<v3s16, MapBlock*>::Iterator
1291                                 i = lighting_modified_blocks.getIterator();
1292                                 i.atEnd() == false; i++)
1293                 {
1294                         MapBlock *block = i.getNode()->getValue();
1295                         modified_blocks.insert(block->getPos(), block);
1296                 }
1297 #endif
1298                 /*
1299                         Set the modified blocks unsent for all the clients
1300                 */
1301                 
1302                 JMutexAutoLock lock2(m_con_mutex);
1303
1304                 for(core::map<u16, RemoteClient*>::Iterator
1305                                 i = m_clients.getIterator();
1306                                 i.atEnd() == false; i++)
1307                 {
1308                         RemoteClient *client = i.getNode()->getValue();
1309                         
1310                         if(modified_blocks.size() > 0)
1311                         {
1312                                 // Remove block from sent history
1313                                 client->SetBlocksNotSent(modified_blocks);
1314                         }
1315                 }
1316         }
1317
1318         // Periodically print some info
1319         {
1320                 float &counter = m_print_info_timer;
1321                 counter += dtime;
1322                 if(counter >= 30.0)
1323                 {
1324                         counter = 0.0;
1325
1326                         JMutexAutoLock lock2(m_con_mutex);
1327                         
1328                         if(m_clients.size() != 0)
1329                                 infostream<<"Players:"<<std::endl;
1330                         for(core::map<u16, RemoteClient*>::Iterator
1331                                 i = m_clients.getIterator();
1332                                 i.atEnd() == false; i++)
1333                         {
1334                                 //u16 peer_id = i.getNode()->getKey();
1335                                 RemoteClient *client = i.getNode()->getValue();
1336                                 Player *player = m_env->getPlayer(client->peer_id);
1337                                 if(player==NULL)
1338                                         continue;
1339                                 infostream<<"* "<<player->getName()<<"\t";
1340                                 client->PrintInfo(infostream);
1341                         }
1342                 }
1343         }
1344
1345         //if(g_settings->getBool("enable_experimental"))
1346         {
1347
1348         /*
1349                 Check added and deleted active objects
1350         */
1351         {
1352                 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1353                 JMutexAutoLock envlock(m_env_mutex);
1354                 JMutexAutoLock conlock(m_con_mutex);
1355
1356                 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1357
1358                 // Radius inside which objects are active
1359                 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1360                 radius *= MAP_BLOCKSIZE;
1361
1362                 for(core::map<u16, RemoteClient*>::Iterator
1363                         i = m_clients.getIterator();
1364                         i.atEnd() == false; i++)
1365                 {
1366                         RemoteClient *client = i.getNode()->getValue();
1367                         Player *player = m_env->getPlayer(client->peer_id);
1368                         if(player==NULL)
1369                         {
1370                                 // This can happen if the client timeouts somehow
1371                                 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1372                                                 <<client->peer_id
1373                                                 <<" has no associated player"<<std::endl;*/
1374                                 continue;
1375                         }
1376                         v3s16 pos = floatToInt(player->getPosition(), BS);
1377
1378                         core::map<u16, bool> removed_objects;
1379                         core::map<u16, bool> added_objects;
1380                         m_env->getRemovedActiveObjects(pos, radius,
1381                                         client->m_known_objects, removed_objects);
1382                         m_env->getAddedActiveObjects(pos, radius,
1383                                         client->m_known_objects, added_objects);
1384                         
1385                         // Ignore if nothing happened
1386                         if(removed_objects.size() == 0 && added_objects.size() == 0)
1387                         {
1388                                 //infostream<<"active objects: none changed"<<std::endl;
1389                                 continue;
1390                         }
1391                         
1392                         std::string data_buffer;
1393
1394                         char buf[4];
1395                         
1396                         // Handle removed objects
1397                         writeU16((u8*)buf, removed_objects.size());
1398                         data_buffer.append(buf, 2);
1399                         for(core::map<u16, bool>::Iterator
1400                                         i = removed_objects.getIterator();
1401                                         i.atEnd()==false; i++)
1402                         {
1403                                 // Get object
1404                                 u16 id = i.getNode()->getKey();
1405                                 ServerActiveObject* obj = m_env->getActiveObject(id);
1406
1407                                 // Add to data buffer for sending
1408                                 writeU16((u8*)buf, i.getNode()->getKey());
1409                                 data_buffer.append(buf, 2);
1410                                 
1411                                 // Remove from known objects
1412                                 client->m_known_objects.remove(i.getNode()->getKey());
1413
1414                                 if(obj && obj->m_known_by_count > 0)
1415                                         obj->m_known_by_count--;
1416                         }
1417
1418                         // Handle added objects
1419                         writeU16((u8*)buf, added_objects.size());
1420                         data_buffer.append(buf, 2);
1421                         for(core::map<u16, bool>::Iterator
1422                                         i = added_objects.getIterator();
1423                                         i.atEnd()==false; i++)
1424                         {
1425                                 // Get object
1426                                 u16 id = i.getNode()->getKey();
1427                                 ServerActiveObject* obj = m_env->getActiveObject(id);
1428                                 
1429                                 // Get object type
1430                                 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1431                                 if(obj == NULL)
1432                                         infostream<<"WARNING: "<<__FUNCTION_NAME
1433                                                         <<": NULL object"<<std::endl;
1434                                 else
1435                                         type = obj->getType();
1436
1437                                 // Add to data buffer for sending
1438                                 writeU16((u8*)buf, id);
1439                                 data_buffer.append(buf, 2);
1440                                 writeU8((u8*)buf, type);
1441                                 data_buffer.append(buf, 1);
1442                                 
1443                                 if(obj)
1444                                         data_buffer.append(serializeLongString(
1445                                                         obj->getClientInitializationData()));
1446                                 else
1447                                         data_buffer.append(serializeLongString(""));
1448
1449                                 // Add to known objects
1450                                 client->m_known_objects.insert(i.getNode()->getKey(), false);
1451
1452                                 if(obj)
1453                                         obj->m_known_by_count++;
1454                         }
1455
1456                         // Send packet
1457                         SharedBuffer<u8> reply(2 + data_buffer.size());
1458                         writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1459                         memcpy((char*)&reply[2], data_buffer.c_str(),
1460                                         data_buffer.size());
1461                         // Send as reliable
1462                         m_con.Send(client->peer_id, 0, reply, true);
1463
1464                         infostream<<"Server: Sent object remove/add: "
1465                                         <<removed_objects.size()<<" removed, "
1466                                         <<added_objects.size()<<" added, "
1467                                         <<"packet size is "<<reply.getSize()<<std::endl;
1468                 }
1469
1470 #if 0
1471                 /*
1472                         Collect a list of all the objects known by the clients
1473                         and report it back to the environment.
1474                 */
1475
1476                 core::map<u16, bool> all_known_objects;
1477
1478                 for(core::map<u16, RemoteClient*>::Iterator
1479                         i = m_clients.getIterator();
1480                         i.atEnd() == false; i++)
1481                 {
1482                         RemoteClient *client = i.getNode()->getValue();
1483                         // Go through all known objects of client
1484                         for(core::map<u16, bool>::Iterator
1485                                         i = client->m_known_objects.getIterator();
1486                                         i.atEnd()==false; i++)
1487                         {
1488                                 u16 id = i.getNode()->getKey();
1489                                 all_known_objects[id] = true;
1490                         }
1491                 }
1492                 
1493                 m_env->setKnownActiveObjects(whatever);
1494 #endif
1495
1496         }
1497
1498         /*
1499                 Send object messages
1500         */
1501         {
1502                 JMutexAutoLock envlock(m_env_mutex);
1503                 JMutexAutoLock conlock(m_con_mutex);
1504
1505                 //ScopeProfiler sp(g_profiler, "Server: sending object messages");
1506
1507                 // Key = object id
1508                 // Value = data sent by object
1509                 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1510
1511                 // Get active object messages from environment
1512                 for(;;)
1513                 {
1514                         ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1515                         if(aom.id == 0)
1516                                 break;
1517                         
1518                         core::list<ActiveObjectMessage>* message_list = NULL;
1519                         core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1520                         n = buffered_messages.find(aom.id);
1521                         if(n == NULL)
1522                         {
1523                                 message_list = new core::list<ActiveObjectMessage>;
1524                                 buffered_messages.insert(aom.id, message_list);
1525                         }
1526                         else
1527                         {
1528                                 message_list = n->getValue();
1529                         }
1530                         message_list->push_back(aom);
1531                 }
1532                 
1533                 // Route data to every client
1534                 for(core::map<u16, RemoteClient*>::Iterator
1535                         i = m_clients.getIterator();
1536                         i.atEnd()==false; i++)
1537                 {
1538                         RemoteClient *client = i.getNode()->getValue();
1539                         std::string reliable_data;
1540                         std::string unreliable_data;
1541                         // Go through all objects in message buffer
1542                         for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1543                                         j = buffered_messages.getIterator();
1544                                         j.atEnd()==false; j++)
1545                         {
1546                                 // If object is not known by client, skip it
1547                                 u16 id = j.getNode()->getKey();
1548                                 if(client->m_known_objects.find(id) == NULL)
1549                                         continue;
1550                                 // Get message list of object
1551                                 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1552                                 // Go through every message
1553                                 for(core::list<ActiveObjectMessage>::Iterator
1554                                                 k = list->begin(); k != list->end(); k++)
1555                                 {
1556                                         // Compose the full new data with header
1557                                         ActiveObjectMessage aom = *k;
1558                                         std::string new_data;
1559                                         // Add object id
1560                                         char buf[2];
1561                                         writeU16((u8*)&buf[0], aom.id);
1562                                         new_data.append(buf, 2);
1563                                         // Add data
1564                                         new_data += serializeString(aom.datastring);
1565                                         // Add data to buffer
1566                                         if(aom.reliable)
1567                                                 reliable_data += new_data;
1568                                         else
1569                                                 unreliable_data += new_data;
1570                                 }
1571                         }
1572                         /*
1573                                 reliable_data and unreliable_data are now ready.
1574                                 Send them.
1575                         */
1576                         if(reliable_data.size() > 0)
1577                         {
1578                                 SharedBuffer<u8> reply(2 + reliable_data.size());
1579                                 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1580                                 memcpy((char*)&reply[2], reliable_data.c_str(),
1581                                                 reliable_data.size());
1582                                 // Send as reliable
1583                                 m_con.Send(client->peer_id, 0, reply, true);
1584                         }
1585                         if(unreliable_data.size() > 0)
1586                         {
1587                                 SharedBuffer<u8> reply(2 + unreliable_data.size());
1588                                 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1589                                 memcpy((char*)&reply[2], unreliable_data.c_str(),
1590                                                 unreliable_data.size());
1591                                 // Send as unreliable
1592                                 m_con.Send(client->peer_id, 0, reply, false);
1593                         }
1594
1595                         /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1596                         {
1597                                 infostream<<"Server: Size of object message data: "
1598                                                 <<"reliable: "<<reliable_data.size()
1599                                                 <<", unreliable: "<<unreliable_data.size()
1600                                                 <<std::endl;
1601                         }*/
1602                 }
1603
1604                 // Clear buffered_messages
1605                 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1606                                 i = buffered_messages.getIterator();
1607                                 i.atEnd()==false; i++)
1608                 {
1609                         delete i.getNode()->getValue();
1610                 }
1611         }
1612
1613         } // enable_experimental
1614
1615         /*
1616                 Send queued-for-sending map edit events.
1617         */
1618         {
1619                 // Don't send too many at a time
1620                 //u32 count = 0;
1621
1622                 // Single change sending is disabled if queue size is not small
1623                 bool disable_single_change_sending = false;
1624                 if(m_unsent_map_edit_queue.size() >= 4)
1625                         disable_single_change_sending = true;
1626
1627                 bool got_any_events = false;
1628
1629                 // We'll log the amount of each
1630                 Profiler prof;
1631
1632                 while(m_unsent_map_edit_queue.size() != 0)
1633                 {
1634                         got_any_events = true;
1635
1636                         MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1637                         
1638                         // Players far away from the change are stored here.
1639                         // Instead of sending the changes, MapBlocks are set not sent
1640                         // for them.
1641                         core::list<u16> far_players;
1642
1643                         if(event->type == MEET_ADDNODE)
1644                         {
1645                                 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1646                                 prof.add("MEET_ADDNODE", 1);
1647                                 if(disable_single_change_sending)
1648                                         sendAddNode(event->p, event->n, event->already_known_by_peer,
1649                                                         &far_players, 5);
1650                                 else
1651                                         sendAddNode(event->p, event->n, event->already_known_by_peer,
1652                                                         &far_players, 30);
1653                         }
1654                         else if(event->type == MEET_REMOVENODE)
1655                         {
1656                                 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1657                                 prof.add("MEET_REMOVENODE", 1);
1658                                 if(disable_single_change_sending)
1659                                         sendRemoveNode(event->p, event->already_known_by_peer,
1660                                                         &far_players, 5);
1661                                 else
1662                                         sendRemoveNode(event->p, event->already_known_by_peer,
1663                                                         &far_players, 30);
1664                         }
1665                         else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1666                         {
1667                                 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1668                                 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1669                                 setBlockNotSent(event->p);
1670                         }
1671                         else if(event->type == MEET_OTHER)
1672                         {
1673                                 infostream<<"Server: MEET_OTHER"<<std::endl;
1674                                 prof.add("MEET_OTHER", 1);
1675                                 for(core::map<v3s16, bool>::Iterator
1676                                                 i = event->modified_blocks.getIterator();
1677                                                 i.atEnd()==false; i++)
1678                                 {
1679                                         v3s16 p = i.getNode()->getKey();
1680                                         setBlockNotSent(p);
1681                                 }
1682                         }
1683                         else
1684                         {
1685                                 prof.add("unknown", 1);
1686                                 infostream<<"WARNING: Server: Unknown MapEditEvent "
1687                                                 <<((u32)event->type)<<std::endl;
1688                         }
1689                         
1690                         /*
1691                                 Set blocks not sent to far players
1692                         */
1693                         if(far_players.size() > 0)
1694                         {
1695                                 // Convert list format to that wanted by SetBlocksNotSent
1696                                 core::map<v3s16, MapBlock*> modified_blocks2;
1697                                 for(core::map<v3s16, bool>::Iterator
1698                                                 i = event->modified_blocks.getIterator();
1699                                                 i.atEnd()==false; i++)
1700                                 {
1701                                         v3s16 p = i.getNode()->getKey();
1702                                         modified_blocks2.insert(p,
1703                                                         m_env->getMap().getBlockNoCreateNoEx(p));
1704                                 }
1705                                 // Set blocks not sent
1706                                 for(core::list<u16>::Iterator
1707                                                 i = far_players.begin();
1708                                                 i != far_players.end(); i++)
1709                                 {
1710                                         u16 peer_id = *i;
1711                                         RemoteClient *client = getClient(peer_id);
1712                                         if(client==NULL)
1713                                                 continue;
1714                                         client->SetBlocksNotSent(modified_blocks2);
1715                                 }
1716                         }
1717
1718                         delete event;
1719
1720                         /*// Don't send too many at a time
1721                         count++;
1722                         if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1723                                 break;*/
1724                 }
1725
1726                 if(got_any_events)
1727                 {
1728                         infostream<<"Server: MapEditEvents:"<<std::endl;
1729                         prof.print(infostream);
1730                 }
1731                 
1732         }
1733
1734         /*
1735                 Send object positions
1736         */
1737         {
1738                 float &counter = m_objectdata_timer;
1739                 counter += dtime;
1740                 if(counter >= g_settings->getFloat("objectdata_interval"))
1741                 {
1742                         JMutexAutoLock lock1(m_env_mutex);
1743                         JMutexAutoLock lock2(m_con_mutex);
1744
1745                         //ScopeProfiler sp(g_profiler, "Server: sending player positions");
1746
1747                         SendObjectData(counter);
1748
1749                         counter = 0.0;
1750                 }
1751         }
1752         
1753         /*
1754                 Trigger emergethread (it somehow gets to a non-triggered but
1755                 bysy state sometimes)
1756         */
1757         {
1758                 float &counter = m_emergethread_trigger_timer;
1759                 counter += dtime;
1760                 if(counter >= 2.0)
1761                 {
1762                         counter = 0.0;
1763                         
1764                         m_emergethread.trigger();
1765                 }
1766         }
1767
1768         // Save map, players and auth stuff
1769         {
1770                 float &counter = m_savemap_timer;
1771                 counter += dtime;
1772                 if(counter >= g_settings->getFloat("server_map_save_interval"))
1773                 {
1774                         counter = 0.0;
1775
1776                         ScopeProfiler sp(g_profiler, "Server: saving stuff");
1777
1778                         // Auth stuff
1779                         if(m_authmanager.isModified())
1780                                 m_authmanager.save();
1781
1782                         //Bann stuff
1783                         if(m_banmanager.isModified())
1784                                 m_banmanager.save();
1785                         
1786                         // Map
1787                         JMutexAutoLock lock(m_env_mutex);
1788
1789                         /*// Unload unused data (delete from memory)
1790                         m_env->getMap().unloadUnusedData(
1791                                         g_settings->getFloat("server_unload_unused_sectors_timeout"));
1792                                         */
1793                         /*u32 deleted_count = m_env->getMap().unloadUnusedData(
1794                                         g_settings->getFloat("server_unload_unused_sectors_timeout"));
1795                                         */
1796
1797                         // Save only changed parts
1798                         m_env->getMap().save(true);
1799
1800                         /*if(deleted_count > 0)
1801                         {
1802                                 infostream<<"Server: Unloaded "<<deleted_count
1803                                                 <<" blocks from memory"<<std::endl;
1804                         }*/
1805
1806                         // Save players
1807                         m_env->serializePlayers(m_mapsavedir);
1808                         
1809                         // Save environment metadata
1810                         m_env->saveMeta(m_mapsavedir);
1811                 }
1812         }
1813 }
1814
1815 void Server::Receive()
1816 {
1817         DSTACK(__FUNCTION_NAME);
1818         SharedBuffer<u8> data;
1819         u16 peer_id;
1820         u32 datasize;
1821         try{
1822                 {
1823                         JMutexAutoLock conlock(m_con_mutex);
1824                         datasize = m_con.Receive(peer_id, data);
1825                 }
1826
1827                 // This has to be called so that the client list gets synced
1828                 // with the peer list of the connection
1829                 handlePeerChanges();
1830
1831                 ProcessData(*data, datasize, peer_id);
1832         }
1833         catch(con::InvalidIncomingDataException &e)
1834         {
1835                 infostream<<"Server::Receive(): "
1836                                 "InvalidIncomingDataException: what()="
1837                                 <<e.what()<<std::endl;
1838         }
1839         catch(con::PeerNotFoundException &e)
1840         {
1841                 //NOTE: This is not needed anymore
1842                 
1843                 // The peer has been disconnected.
1844                 // Find the associated player and remove it.
1845
1846                 /*JMutexAutoLock envlock(m_env_mutex);
1847
1848                 infostream<<"ServerThread: peer_id="<<peer_id
1849                                 <<" has apparently closed connection. "
1850                                 <<"Removing player."<<std::endl;
1851
1852                 m_env->removePlayer(peer_id);*/
1853         }
1854 }
1855
1856 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1857 {
1858         DSTACK(__FUNCTION_NAME);
1859         // Environment is locked first.
1860         JMutexAutoLock envlock(m_env_mutex);
1861         JMutexAutoLock conlock(m_con_mutex);
1862         
1863         try{
1864                 Address address = m_con.GetPeerAddress(peer_id);
1865
1866                 // drop player if is ip is banned
1867                 if(m_banmanager.isIpBanned(address.serializeString())){
1868                         SendAccessDenied(m_con, peer_id,
1869                                         L"Your ip is banned. Banned name was "
1870                                         +narrow_to_wide(m_banmanager.getBanName(
1871                                                 address.serializeString())));
1872                         m_con.DeletePeer(peer_id);
1873                         return;
1874                 }
1875         }
1876         catch(con::PeerNotFoundException &e)
1877         {
1878                 infostream<<"Server::ProcessData(): Cancelling: peer "
1879                                 <<peer_id<<" not found"<<std::endl;
1880                 return;
1881         }
1882
1883         u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1884
1885         try
1886         {
1887
1888         if(datasize < 2)
1889                 return;
1890
1891         ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1892         
1893         if(command == TOSERVER_INIT)
1894         {
1895                 // [0] u16 TOSERVER_INIT
1896                 // [2] u8 SER_FMT_VER_HIGHEST
1897                 // [3] u8[20] player_name
1898                 // [23] u8[28] password <--- can be sent without this, from old versions
1899
1900                 if(datasize < 2+1+PLAYERNAME_SIZE)
1901                         return;
1902
1903                 infostream<<"Server: Got TOSERVER_INIT from "
1904                                 <<peer_id<<std::endl;
1905
1906                 // First byte after command is maximum supported
1907                 // serialization version
1908                 u8 client_max = data[2];
1909                 u8 our_max = SER_FMT_VER_HIGHEST;
1910                 // Use the highest version supported by both
1911                 u8 deployed = core::min_(client_max, our_max);
1912                 // If it's lower than the lowest supported, give up.
1913                 if(deployed < SER_FMT_VER_LOWEST)
1914                         deployed = SER_FMT_VER_INVALID;
1915
1916                 //peer->serialization_version = deployed;
1917                 getClient(peer_id)->pending_serialization_version = deployed;
1918                 
1919                 if(deployed == SER_FMT_VER_INVALID)
1920                 {
1921                         infostream<<"Server: Cannot negotiate "
1922                                         "serialization version with peer "
1923                                         <<peer_id<<std::endl;
1924                         SendAccessDenied(m_con, peer_id,
1925                                         L"Your client is too old (map format)");
1926                         return;
1927                 }
1928                 
1929                 /*
1930                         Read and check network protocol version
1931                 */
1932
1933                 u16 net_proto_version = 0;
1934                 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1935                 {
1936                         net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1937                 }
1938
1939                 getClient(peer_id)->net_proto_version = net_proto_version;
1940
1941                 if(net_proto_version == 0)
1942                 {
1943                         SendAccessDenied(m_con, peer_id,
1944                                         L"Your client is too old. Please upgrade.");
1945                         return;
1946                 }
1947                 
1948                 /* Uhh... this should actually be a warning but let's do it like this */
1949                 if(g_settings->getBool("strict_protocol_version_checking"))
1950                 {
1951                         if(net_proto_version < PROTOCOL_VERSION)
1952                         {
1953                                 SendAccessDenied(m_con, peer_id,
1954                                                 L"Your client is too old. Please upgrade.");
1955                                 return;
1956                         }
1957                 }
1958
1959                 /*
1960                         Set up player
1961                 */
1962                 
1963                 // Get player name
1964                 char playername[PLAYERNAME_SIZE];
1965                 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1966                 {
1967                         playername[i] = data[3+i];
1968                 }
1969                 playername[PLAYERNAME_SIZE-1] = 0;
1970                 
1971                 if(playername[0]=='\0')
1972                 {
1973                         infostream<<"Server: Player has empty name"<<std::endl;
1974                         SendAccessDenied(m_con, peer_id,
1975                                         L"Empty name");
1976                         return;
1977                 }
1978
1979                 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1980                 {
1981                         infostream<<"Server: Player has invalid name"<<std::endl;
1982                         SendAccessDenied(m_con, peer_id,
1983                                         L"Name contains unallowed characters");
1984                         return;
1985                 }
1986
1987                 // Get password
1988                 char password[PASSWORD_SIZE];
1989                 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1990                 {
1991                         // old version - assume blank password
1992                         password[0] = 0;
1993                 }
1994                 else
1995                 {
1996                                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1997                                 {
1998                                         password[i] = data[23+i];
1999                                 }
2000                                 password[PASSWORD_SIZE-1] = 0;
2001                 }
2002                 
2003                 std::string checkpwd;
2004                 if(m_authmanager.exists(playername))
2005                 {
2006                         checkpwd = m_authmanager.getPassword(playername);
2007                 }
2008                 else
2009                 {
2010                         checkpwd = g_settings->get("default_password");
2011                 }
2012                 
2013                 /*infostream<<"Server: Client gave password '"<<password
2014                                 <<"', the correct one is '"<<checkpwd<<"'"<<std::endl;*/
2015                 
2016                 if(password != checkpwd && m_authmanager.exists(playername))
2017                 {
2018                         infostream<<"Server: peer_id="<<peer_id
2019                                         <<": supplied invalid password for "
2020                                         <<playername<<std::endl;
2021                         SendAccessDenied(m_con, peer_id, L"Invalid password");
2022                         return;
2023                 }
2024                 
2025                 // Add player to auth manager
2026                 if(m_authmanager.exists(playername) == false)
2027                 {
2028                         infostream<<"Server: adding player "<<playername
2029                                         <<" to auth manager"<<std::endl;
2030                         m_authmanager.add(playername);
2031                         m_authmanager.setPassword(playername, checkpwd);
2032                         m_authmanager.setPrivs(playername,
2033                                         stringToPrivs(g_settings->get("default_privs")));
2034                         m_authmanager.save();
2035                 }
2036                 
2037                 // Enforce user limit.
2038                 // Don't enforce for users that have some admin right
2039                 if(m_clients.size() >= g_settings->getU16("max_users") &&
2040                                 (m_authmanager.getPrivs(playername)
2041                                         & (PRIV_SERVER|PRIV_BAN|PRIV_PRIVS)) == 0 &&
2042                                 playername != g_settings->get("name"))
2043                 {
2044                         SendAccessDenied(m_con, peer_id, L"Too many users.");
2045                         return;
2046                 }
2047
2048                 // Get player
2049                 Player *player = emergePlayer(playername, password, peer_id);
2050
2051                 // If failed, cancel
2052                 if(player == NULL)
2053                 {
2054                         infostream<<"Server: peer_id="<<peer_id
2055                                         <<": failed to emerge player"<<std::endl;
2056                         return;
2057                 }
2058
2059                 /*
2060                         Answer with a TOCLIENT_INIT
2061                 */
2062                 {
2063                         SharedBuffer<u8> reply(2+1+6+8);
2064                         writeU16(&reply[0], TOCLIENT_INIT);
2065                         writeU8(&reply[2], deployed);
2066                         writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2067                         writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2068                         
2069                         // Send as reliable
2070                         m_con.Send(peer_id, 0, reply, true);
2071                 }
2072
2073                 /*
2074                         Send complete position information
2075                 */
2076                 SendMovePlayer(player);
2077
2078                 return;
2079         }
2080
2081         if(command == TOSERVER_INIT2)
2082         {
2083                 infostream<<"Server: Got TOSERVER_INIT2 from "
2084                                 <<peer_id<<std::endl;
2085
2086
2087                 getClient(peer_id)->serialization_version
2088                                 = getClient(peer_id)->pending_serialization_version;
2089
2090                 /*
2091                         Send some initialization data
2092                 */
2093                 
2094                 // Send player info to all players
2095                 SendPlayerInfos();
2096
2097                 // Send inventory to player
2098                 UpdateCrafting(peer_id);
2099                 SendInventory(peer_id);
2100
2101                 // Send player items to all players
2102                 SendPlayerItems();
2103
2104                 Player *player = m_env->getPlayer(peer_id);
2105
2106                 // Send HP
2107                 SendPlayerHP(player);
2108                 
2109                 // Send time of day
2110                 {
2111                         SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2112                                         m_env->getTimeOfDay());
2113                         m_con.Send(peer_id, 0, data, true);
2114                 }
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 game";
2130                         BroadcastChatMessage(message);
2131                 }
2132                 
2133                 // Warnings about protocol version can be issued here
2134                 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2135                 {
2136                         SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER");
2137                 }
2138
2139                 /*
2140                         Check HP, respawn if necessary
2141                 */
2142                 HandlePlayerHP(player, 0);
2143
2144                 /*
2145                         Print out action
2146                 */
2147                 {
2148                         std::ostringstream os(std::ios_base::binary);
2149                         for(core::map<u16, RemoteClient*>::Iterator
2150                                 i = m_clients.getIterator();
2151                                 i.atEnd() == false; i++)
2152                         {
2153                                 RemoteClient *client = i.getNode()->getValue();
2154                                 assert(client->peer_id == i.getNode()->getKey());
2155                                 if(client->serialization_version == SER_FMT_VER_INVALID)
2156                                         continue;
2157                                 // Get player
2158                                 Player *player = m_env->getPlayer(client->peer_id);
2159                                 if(!player)
2160                                         continue;
2161                                 // Get name of player
2162                                 os<<player->getName()<<" ";
2163                         }
2164
2165                         actionstream<<player->getName()<<" joins game. List of players: "
2166                                         <<os.str()<<std::endl;
2167                 }
2168
2169                 return;
2170         }
2171
2172         if(peer_ser_ver == SER_FMT_VER_INVALID)
2173         {
2174                 infostream<<"Server::ProcessData(): Cancelling: Peer"
2175                                 " serialization format invalid or not initialized."
2176                                 " Skipping incoming command="<<command<<std::endl;
2177                 return;
2178         }
2179         
2180         Player *player = m_env->getPlayer(peer_id);
2181
2182         if(player == NULL){
2183                 infostream<<"Server::ProcessData(): Cancelling: "
2184                                 "No player for peer_id="<<peer_id
2185                                 <<std::endl;
2186                 return;
2187         }
2188         if(command == TOSERVER_PLAYERPOS)
2189         {
2190                 if(datasize < 2+12+12+4+4)
2191                         return;
2192         
2193                 u32 start = 0;
2194                 v3s32 ps = readV3S32(&data[start+2]);
2195                 v3s32 ss = readV3S32(&data[start+2+12]);
2196                 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2197                 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2198                 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2199                 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2200                 pitch = wrapDegrees(pitch);
2201                 yaw = wrapDegrees(yaw);
2202
2203                 player->setPosition(position);
2204                 player->setSpeed(speed);
2205                 player->setPitch(pitch);
2206                 player->setYaw(yaw);
2207                 
2208                 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2209                                 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2210                                 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2211         }
2212         else if(command == TOSERVER_GOTBLOCKS)
2213         {
2214                 if(datasize < 2+1)
2215                         return;
2216                 
2217                 /*
2218                         [0] u16 command
2219                         [2] u8 count
2220                         [3] v3s16 pos_0
2221                         [3+6] v3s16 pos_1
2222                         ...
2223                 */
2224
2225                 u16 count = data[2];
2226                 for(u16 i=0; i<count; i++)
2227                 {
2228                         if((s16)datasize < 2+1+(i+1)*6)
2229                                 throw con::InvalidIncomingDataException
2230                                         ("GOTBLOCKS length is too short");
2231                         v3s16 p = readV3S16(&data[2+1+i*6]);
2232                         /*infostream<<"Server: GOTBLOCKS ("
2233                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2234                         RemoteClient *client = getClient(peer_id);
2235                         client->GotBlock(p);
2236                 }
2237         }
2238         else if(command == TOSERVER_DELETEDBLOCKS)
2239         {
2240                 if(datasize < 2+1)
2241                         return;
2242                 
2243                 /*
2244                         [0] u16 command
2245                         [2] u8 count
2246                         [3] v3s16 pos_0
2247                         [3+6] v3s16 pos_1
2248                         ...
2249                 */
2250
2251                 u16 count = data[2];
2252                 for(u16 i=0; i<count; i++)
2253                 {
2254                         if((s16)datasize < 2+1+(i+1)*6)
2255                                 throw con::InvalidIncomingDataException
2256                                         ("DELETEDBLOCKS length is too short");
2257                         v3s16 p = readV3S16(&data[2+1+i*6]);
2258                         /*infostream<<"Server: DELETEDBLOCKS ("
2259                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2260                         RemoteClient *client = getClient(peer_id);
2261                         client->SetBlockNotSent(p);
2262                 }
2263         }
2264         else if(command == TOSERVER_CLICK_OBJECT)
2265         {
2266                 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2267                 return;
2268         }
2269         else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2270         {
2271                 if(datasize < 7)
2272                         return;
2273
2274                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2275                         return;
2276
2277                 /*
2278                         length: 7
2279                         [0] u16 command
2280                         [2] u8 button (0=left, 1=right)
2281                         [3] u16 id
2282                         [5] u16 item
2283                 */
2284                 u8 button = readU8(&data[2]);
2285                 u16 id = readS16(&data[3]);
2286                 u16 item_i = readU16(&data[5]);
2287         
2288                 ServerActiveObject *obj = m_env->getActiveObject(id);
2289
2290                 if(obj == NULL)
2291                 {
2292                         infostream<<"Server: CLICK_ACTIVEOBJECT: object not found"
2293                                         <<std::endl;
2294                         return;
2295                 }
2296
2297                 // Skip if object has been removed
2298                 if(obj->m_removed)
2299                         return;
2300                 
2301                 //TODO: Check that object is reasonably close
2302                 
2303                 // Left click, pick object up (usually)
2304                 if(button == 0)
2305                 {
2306                         /*
2307                                 Try creating inventory item
2308                         */
2309                         InventoryItem *item = obj->createPickedUpItem();
2310                         
2311                         if(item)
2312                         {
2313                                 InventoryList *ilist = player->inventory.getList("main");
2314                                 if(ilist != NULL)
2315                                 {
2316                                         actionstream<<player->getName()<<" picked up "
2317                                                         <<item->getName()<<std::endl;
2318                                         if(g_settings->getBool("creative_mode") == false)
2319                                         {
2320                                                 // Skip if inventory has no free space
2321                                                 if(ilist->roomForItem(item) == false)
2322                                                 {
2323                                                         infostream<<"Player inventory has no free space"<<std::endl;
2324                                                         return;
2325                                                 }
2326
2327                                                 // Add to inventory and send inventory
2328                                                 ilist->addItem(item);
2329                                                 UpdateCrafting(player->peer_id);
2330                                                 SendInventory(player->peer_id);
2331                                         }
2332
2333                                         // Remove object from environment
2334                                         obj->m_removed = true;
2335                                 }
2336                         }
2337                         else
2338                         {
2339                                 /*
2340                                         Item cannot be picked up. Punch it instead.
2341                                 */
2342
2343                                 actionstream<<player->getName()<<" punches object "
2344                                                 <<obj->getId()<<std::endl;
2345
2346                                 ToolItem *titem = NULL;
2347                                 std::string toolname = "";
2348
2349                                 InventoryList *mlist = player->inventory.getList("main");
2350                                 if(mlist != NULL)
2351                                 {
2352                                         InventoryItem *item = mlist->getItem(item_i);
2353                                         if(item && (std::string)item->getName() == "ToolItem")
2354                                         {
2355                                                 titem = (ToolItem*)item;
2356                                                 toolname = titem->getToolName();
2357                                         }
2358                                 }
2359
2360                                 v3f playerpos = player->getPosition();
2361                                 v3f objpos = obj->getBasePosition();
2362                                 v3f dir = (objpos - playerpos).normalize();
2363                                 
2364                                 u16 wear = obj->punch(toolname, dir, player->getName());
2365                                 
2366                                 if(titem)
2367                                 {
2368                                         bool weared_out = titem->addWear(wear);
2369                                         if(weared_out)
2370                                                 mlist->deleteItem(item_i);
2371                                         SendInventory(player->peer_id);
2372                                 }
2373                         }
2374                 }
2375                 // Right click, do something with object
2376                 if(button == 1)
2377                 {
2378                         actionstream<<player->getName()<<" right clicks object "
2379                                         <<obj->getId()<<std::endl;
2380
2381                         // Track hp changes super-crappily
2382                         u16 oldhp = player->hp;
2383                         
2384                         // Do stuff
2385                         obj->rightClick(player);
2386                         
2387                         // Send back stuff
2388                         if(player->hp != oldhp)
2389                         {
2390                                 SendPlayerHP(player);
2391                         }
2392                 }
2393         }
2394         else if(command == TOSERVER_GROUND_ACTION)
2395         {
2396                 if(datasize < 17)
2397                         return;
2398                 /*
2399                         length: 17
2400                         [0] u16 command
2401                         [2] u8 action
2402                         [3] v3s16 nodepos_undersurface
2403                         [9] v3s16 nodepos_abovesurface
2404                         [15] u16 item
2405                         actions:
2406                         0: start digging
2407                         1: place block
2408                         2: stop digging (all parameters ignored)
2409                         3: digging completed
2410                 */
2411                 u8 action = readU8(&data[2]);
2412                 v3s16 p_under;
2413                 p_under.X = readS16(&data[3]);
2414                 p_under.Y = readS16(&data[5]);
2415                 p_under.Z = readS16(&data[7]);
2416                 v3s16 p_over;
2417                 p_over.X = readS16(&data[9]);
2418                 p_over.Y = readS16(&data[11]);
2419                 p_over.Z = readS16(&data[13]);
2420                 u16 item_i = readU16(&data[15]);
2421
2422                 //TODO: Check that target is reasonably close
2423                 
2424                 /*
2425                         0: start digging
2426                 */
2427                 if(action == 0)
2428                 {
2429                         /*
2430                                 NOTE: This can be used in the future to check if
2431                                 somebody is cheating, by checking the timing.
2432                         */
2433                 } // action == 0
2434
2435                 /*
2436                         2: stop digging
2437                 */
2438                 else if(action == 2)
2439                 {
2440 #if 0
2441                         RemoteClient *client = getClient(peer_id);
2442                         JMutexAutoLock digmutex(client->m_dig_mutex);
2443                         client->m_dig_tool_item = -1;
2444 #endif
2445                 }
2446
2447                 /*
2448                         3: Digging completed
2449                 */
2450                 else if(action == 3)
2451                 {
2452                         // Mandatory parameter; actually used for nothing
2453                         core::map<v3s16, MapBlock*> modified_blocks;
2454
2455                         content_t material = CONTENT_IGNORE;
2456                         u8 mineral = MINERAL_NONE;
2457
2458                         bool cannot_remove_node = false;
2459
2460                         try
2461                         {
2462                                 MapNode n = m_env->getMap().getNode(p_under);
2463                                 // Get mineral
2464                                 mineral = n.getMineral();
2465                                 // Get material at position
2466                                 material = n.getContent();
2467                                 // If not yet cancelled
2468                                 if(cannot_remove_node == false)
2469                                 {
2470                                         // If it's not diggable, do nothing
2471                                         if(content_diggable(material) == false)
2472                                         {
2473                                                 infostream<<"Server: Not finishing digging: "
2474                                                                 <<"Node not diggable"
2475                                                                 <<std::endl;
2476                                                 cannot_remove_node = true;
2477                                         }
2478                                 }
2479                                 // If not yet cancelled
2480                                 if(cannot_remove_node == false)
2481                                 {
2482                                         // Get node metadata
2483                                         NodeMetadata *meta = m_env->getMap().getNodeMetadata(p_under);
2484                                         if(meta && meta->nodeRemovalDisabled() == true)
2485                                         {
2486                                                 infostream<<"Server: Not finishing digging: "
2487                                                                 <<"Node metadata disables removal"
2488                                                                 <<std::endl;
2489                                                 cannot_remove_node = true;
2490                                         }
2491                                 }
2492                         }
2493                         catch(InvalidPositionException &e)
2494                         {
2495                                 infostream<<"Server: Not finishing digging: Node not found."
2496                                                 <<" Adding block to emerge queue."
2497                                                 <<std::endl;
2498                                 m_emerge_queue.addBlock(peer_id,
2499                                                 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2500                                 cannot_remove_node = true;
2501                         }
2502
2503                         // Make sure the player is allowed to do it
2504                         if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2505                         {
2506                                 infostream<<"Player "<<player->getName()<<" cannot remove node"
2507                                                 <<" because privileges are "<<getPlayerPrivs(player)
2508                                                 <<std::endl;
2509                                 cannot_remove_node = true;
2510                         }
2511
2512                         /*
2513                                 If node can't be removed, set block to be re-sent to
2514                                 client and quit.
2515                         */
2516                         if(cannot_remove_node)
2517                         {
2518                                 infostream<<"Server: Not finishing digging."<<std::endl;
2519
2520                                 // Client probably has wrong data.
2521                                 // Set block not sent, so that client will get
2522                                 // a valid one.
2523                                 infostream<<"Client "<<peer_id<<" tried to dig "
2524                                                 <<"node; but node cannot be removed."
2525                                                 <<" setting MapBlock not sent."<<std::endl;
2526                                 RemoteClient *client = getClient(peer_id);
2527                                 v3s16 blockpos = getNodeBlockPos(p_under);
2528                                 client->SetBlockNotSent(blockpos);
2529                                         
2530                                 return;
2531                         }
2532                         
2533                         actionstream<<player->getName()<<" digs "<<PP(p_under)
2534                                         <<", gets material "<<(int)material<<", mineral "
2535                                         <<(int)mineral<<std::endl;
2536                         
2537                         /*
2538                                 Send the removal to all close-by players.
2539                                 - If other player is close, send REMOVENODE
2540                                 - Otherwise set blocks not sent
2541                         */
2542                         core::list<u16> far_players;
2543                         sendRemoveNode(p_under, peer_id, &far_players, 30);
2544                         
2545                         /*
2546                                 Update and send inventory
2547                         */
2548
2549                         if(g_settings->getBool("creative_mode") == false)
2550                         {
2551                                 /*
2552                                         Wear out tool
2553                                 */
2554                                 InventoryList *mlist = player->inventory.getList("main");
2555                                 if(mlist != NULL)
2556                                 {
2557                                         InventoryItem *item = mlist->getItem(item_i);
2558                                         if(item && (std::string)item->getName() == "ToolItem")
2559                                         {
2560                                                 ToolItem *titem = (ToolItem*)item;
2561                                                 std::string toolname = titem->getToolName();
2562
2563                                                 // Get digging properties for material and tool
2564                                                 DiggingProperties prop =
2565                                                                 getDiggingProperties(material, toolname);
2566
2567                                                 if(prop.diggable == false)
2568                                                 {
2569                                                         infostream<<"Server: WARNING: Player digged"
2570                                                                         <<" with impossible material + tool"
2571                                                                         <<" combination"<<std::endl;
2572                                                 }
2573                                                 
2574                                                 bool weared_out = titem->addWear(prop.wear);
2575
2576                                                 if(weared_out)
2577                                                 {
2578                                                         mlist->deleteItem(item_i);
2579                                                 }
2580                                         }
2581                                 }
2582
2583                                 /*
2584                                         Add dug item to inventory
2585                                 */
2586
2587                                 InventoryItem *item = NULL;
2588
2589                                 if(mineral != MINERAL_NONE)
2590                                         item = getDiggedMineralItem(mineral);
2591                                 
2592                                 // If not mineral
2593                                 if(item == NULL)
2594                                 {
2595                                         std::string &dug_s = content_features(material).dug_item;
2596                                         if(dug_s != "")
2597                                         {
2598                                                 std::istringstream is(dug_s, std::ios::binary);
2599                                                 item = InventoryItem::deSerialize(is);
2600                                         }
2601                                 }
2602                                 
2603                                 if(item != NULL)
2604                                 {
2605                                         // Add a item to inventory
2606                                         player->inventory.addItem("main", item);
2607
2608                                         // Send inventory
2609                                         UpdateCrafting(player->peer_id);
2610                                         SendInventory(player->peer_id);
2611                                 }
2612
2613                                 item = NULL;
2614
2615                                 if(mineral != MINERAL_NONE)
2616                                   item = getDiggedMineralItem(mineral);
2617                         
2618                                 // If not mineral
2619                                 if(item == NULL)
2620                                 {
2621                                         std::string &extra_dug_s = content_features(material).extra_dug_item;
2622                                         s32 extra_rarity = content_features(material).extra_dug_item_rarity;
2623                                         if(extra_dug_s != "" && extra_rarity != 0
2624                                            && myrand() % extra_rarity == 0)
2625                                         {
2626                                                 std::istringstream is(extra_dug_s, std::ios::binary);
2627                                                 item = InventoryItem::deSerialize(is);
2628                                         }
2629                                 }
2630                         
2631                                 if(item != NULL)
2632                                 {
2633                                         // Add a item to inventory
2634                                         player->inventory.addItem("main", item);
2635
2636                                         // Send inventory
2637                                         UpdateCrafting(player->peer_id);
2638                                         SendInventory(player->peer_id);
2639                                 }
2640                         }
2641
2642                         /*
2643                                 Remove the node
2644                                 (this takes some time so it is done after the quick stuff)
2645                         */
2646                         {
2647                                 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2648
2649                                 m_env->getMap().removeNodeAndUpdate(p_under, modified_blocks);
2650                         }
2651                         /*
2652                                 Set blocks not sent to far players
2653                         */
2654                         for(core::list<u16>::Iterator
2655                                         i = far_players.begin();
2656                                         i != far_players.end(); i++)
2657                         {
2658                                 u16 peer_id = *i;
2659                                 RemoteClient *client = getClient(peer_id);
2660                                 if(client==NULL)
2661                                         continue;
2662                                 client->SetBlocksNotSent(modified_blocks);
2663                         }
2664                 }
2665                 
2666                 /*
2667                         1: place block
2668                 */
2669                 else if(action == 1)
2670                 {
2671
2672                         InventoryList *ilist = player->inventory.getList("main");
2673                         if(ilist == NULL)
2674                                 return;
2675
2676                         // Get item
2677                         InventoryItem *item = ilist->getItem(item_i);
2678                         
2679                         // If there is no item, it is not possible to add it anywhere
2680                         if(item == NULL)
2681                                 return;
2682                         
2683                         /*
2684                                 Handle material items
2685                         */
2686                         if(std::string("MaterialItem") == item->getName())
2687                         {
2688                                 try{
2689                                         // Don't add a node if this is not a free space
2690                                         MapNode n2 = m_env->getMap().getNode(p_over);
2691                                         bool no_enough_privs =
2692                                                         ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2693                                         if(no_enough_privs)
2694                                                 infostream<<"Player "<<player->getName()<<" cannot add node"
2695                                                         <<" because privileges are "<<getPlayerPrivs(player)
2696                                                         <<std::endl;
2697
2698                                         if(content_features(n2).buildable_to == false
2699                                                 || no_enough_privs)
2700                                         {
2701                                                 // Client probably has wrong data.
2702                                                 // Set block not sent, so that client will get
2703                                                 // a valid one.
2704                                                 infostream<<"Client "<<peer_id<<" tried to place"
2705                                                                 <<" node in invalid position; setting"
2706                                                                 <<" MapBlock not sent."<<std::endl;
2707                                                 RemoteClient *client = getClient(peer_id);
2708                                                 v3s16 blockpos = getNodeBlockPos(p_over);
2709                                                 client->SetBlockNotSent(blockpos);
2710                                                 return;
2711                                         }
2712                                 }
2713                                 catch(InvalidPositionException &e)
2714                                 {
2715                                         infostream<<"Server: Ignoring ADDNODE: Node not found"
2716                                                         <<" Adding block to emerge queue."
2717                                                         <<std::endl;
2718                                         m_emerge_queue.addBlock(peer_id,
2719                                                         getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2720                                         return;
2721                                 }
2722
2723                                 // Reset build time counter
2724                                 getClient(peer_id)->m_time_from_building = 0.0;
2725                                 
2726                                 // Create node data
2727                                 MaterialItem *mitem = (MaterialItem*)item;
2728                                 MapNode n;
2729                                 n.setContent(mitem->getMaterial());
2730
2731                                 actionstream<<player->getName()<<" places material "
2732                                                 <<(int)mitem->getMaterial()
2733                                                 <<" at "<<PP(p_under)<<std::endl;
2734                         
2735                                 // Calculate direction for wall mounted stuff
2736                                 if(content_features(n).wall_mounted)
2737                                         n.param2 = packDir(p_under - p_over);
2738
2739                                 // Calculate the direction for furnaces and chests and stuff
2740                                 if(content_features(n).param_type == CPT_FACEDIR_SIMPLE)
2741                                 {
2742                                         v3f playerpos = player->getPosition();
2743                                         v3f blockpos = intToFloat(p_over, BS) - playerpos;
2744                                         blockpos = blockpos.normalize();
2745                                         n.param1 = 0;
2746                                         if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2747                                                 if (blockpos.X < 0)
2748                                                         n.param1 = 3;
2749                                                 else
2750                                                         n.param1 = 1;
2751                                         } else {
2752                                                 if (blockpos.Z < 0)
2753                                                         n.param1 = 2;
2754                                                 else
2755                                                         n.param1 = 0;
2756                                         }
2757                                 }
2758
2759                                 /*
2760                                         Send to all close-by players
2761                                 */
2762                                 core::list<u16> far_players;
2763                                 sendAddNode(p_over, n, 0, &far_players, 30);
2764                                 
2765                                 /*
2766                                         Handle inventory
2767                                 */
2768                                 InventoryList *ilist = player->inventory.getList("main");
2769                                 if(g_settings->getBool("creative_mode") == false && ilist)
2770                                 {
2771                                         // Remove from inventory and send inventory
2772                                         if(mitem->getCount() == 1)
2773                                                 ilist->deleteItem(item_i);
2774                                         else
2775                                                 mitem->remove(1);
2776                                         // Send inventory
2777                                         UpdateCrafting(peer_id);
2778                                         SendInventory(peer_id);
2779                                 }
2780                                 
2781                                 /*
2782                                         Add node.
2783
2784                                         This takes some time so it is done after the quick stuff
2785                                 */
2786                                 core::map<v3s16, MapBlock*> modified_blocks;
2787                                 {
2788                                         MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2789
2790                                         std::string p_name = std::string(player->getName());
2791                                         m_env->getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name);
2792                                 }
2793                                 /*
2794                                         Set blocks not sent to far players
2795                                 */
2796                                 for(core::list<u16>::Iterator
2797                                                 i = far_players.begin();
2798                                                 i != far_players.end(); i++)
2799                                 {
2800                                         u16 peer_id = *i;
2801                                         RemoteClient *client = getClient(peer_id);
2802                                         if(client==NULL)
2803                                                 continue;
2804                                         client->SetBlocksNotSent(modified_blocks);
2805                                 }
2806
2807                                 /*
2808                                         Calculate special events
2809                                 */
2810                                 
2811                                 /*if(n.d == CONTENT_MESE)
2812                                 {
2813                                         u32 count = 0;
2814                                         for(s16 z=-1; z<=1; z++)
2815                                         for(s16 y=-1; y<=1; y++)
2816                                         for(s16 x=-1; x<=1; x++)
2817                                         {
2818                                                 
2819                                         }
2820                                 }*/
2821                         }
2822                         /*
2823                                 Place other item (not a block)
2824                         */
2825                         else
2826                         {
2827                                 v3s16 blockpos = getNodeBlockPos(p_over);
2828                                 
2829                                 /*
2830                                         Check that the block is loaded so that the item
2831                                         can properly be added to the static list too
2832                                 */
2833                                 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2834                                 if(block==NULL)
2835                                 {
2836                                         infostream<<"Error while placing object: "
2837                                                         "block not found"<<std::endl;
2838                                         return;
2839                                 }
2840
2841                                 /*
2842                                         If in creative mode, item dropping is disabled unless
2843                                         player has build privileges
2844                                 */
2845                                 if(g_settings->getBool("creative_mode") &&
2846                                         (getPlayerPrivs(player) & PRIV_BUILD) == 0)
2847                                 {
2848                                         infostream<<"Not allowing player to drop item: "
2849                                                         "creative mode and no build privs"<<std::endl;
2850                                         return;
2851                                 }
2852
2853                                 // Calculate a position for it
2854                                 v3f pos = intToFloat(p_over, BS);
2855                                 //pos.Y -= BS*0.45;
2856                                 pos.Y -= BS*0.25; // let it drop a bit
2857                                 // Randomize a bit
2858                                 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2859                                 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2860
2861                                 /*
2862                                         Create the object
2863                                 */
2864                                 ServerActiveObject *obj = item->createSAO(m_env, 0, pos);
2865
2866                                 if(obj == NULL)
2867                                 {
2868                                         infostream<<"WARNING: item resulted in NULL object, "
2869                                                         <<"not placing onto map"
2870                                                         <<std::endl;
2871                                 }
2872                                 else
2873                                 {
2874                                         actionstream<<player->getName()<<" places "<<item->getName()
2875                                                         <<" at "<<PP(p_over)<<std::endl;
2876                                 
2877                                         // Add the object to the environment
2878                                         m_env->addActiveObject(obj);
2879                                         
2880                                         infostream<<"Placed object"<<std::endl;
2881
2882                                         if(g_settings->getBool("creative_mode") == false)
2883                                         {
2884                                                 // Delete the right amount of items from the slot
2885                                                 u16 dropcount = item->getDropCount();
2886                                                 
2887                                                 // Delete item if all gone
2888                                                 if(item->getCount() <= dropcount)
2889                                                 {
2890                                                         if(item->getCount() < dropcount)
2891                                                                 infostream<<"WARNING: Server: dropped more items"
2892                                                                                 <<" than the slot contains"<<std::endl;
2893                                                         
2894                                                         InventoryList *ilist = player->inventory.getList("main");
2895                                                         if(ilist)
2896                                                                 // Remove from inventory and send inventory
2897                                                                 ilist->deleteItem(item_i);
2898                                                 }
2899                                                 // Else decrement it
2900                                                 else
2901                                                         item->remove(dropcount);
2902                                                 
2903                                                 // Send inventory
2904                                                 UpdateCrafting(peer_id);
2905                                                 SendInventory(peer_id);
2906                                         }
2907                                 }
2908                         }
2909
2910                 } // action == 1
2911
2912                 /*
2913                         Catch invalid actions
2914                 */
2915                 else
2916                 {
2917                         infostream<<"WARNING: Server: Invalid action "
2918                                         <<action<<std::endl;
2919                 }
2920         }
2921 #if 0
2922         else if(command == TOSERVER_RELEASE)
2923         {
2924                 if(datasize < 3)
2925                         return;
2926                 /*
2927                         length: 3
2928                         [0] u16 command
2929                         [2] u8 button
2930                 */
2931                 infostream<<"TOSERVER_RELEASE ignored"<<std::endl;
2932         }
2933 #endif
2934         else if(command == TOSERVER_SIGNTEXT)
2935         {
2936                 infostream<<"Server: TOSERVER_SIGNTEXT not supported anymore"
2937                                 <<std::endl;
2938                 return;
2939         }
2940         else if(command == TOSERVER_SIGNNODETEXT)
2941         {
2942                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2943                         return;
2944                 /*
2945                         u16 command
2946                         v3s16 p
2947                         u16 textlen
2948                         textdata
2949                 */
2950                 std::string datastring((char*)&data[2], datasize-2);
2951                 std::istringstream is(datastring, std::ios_base::binary);
2952                 u8 buf[6];
2953                 // Read stuff
2954                 is.read((char*)buf, 6);
2955                 v3s16 p = readV3S16(buf);
2956                 is.read((char*)buf, 2);
2957                 u16 textlen = readU16(buf);
2958                 std::string text;
2959                 for(u16 i=0; i<textlen; i++)
2960                 {
2961                         is.read((char*)buf, 1);
2962                         text += (char)buf[0];
2963                 }
2964
2965                 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
2966                 if(!meta)
2967                         return;
2968                 if(meta->typeId() != CONTENT_SIGN_WALL)
2969                         return;
2970                 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
2971                 signmeta->setText(text);
2972                 
2973                 actionstream<<player->getName()<<" writes \""<<text<<"\" to sign "
2974                                 <<" at "<<PP(p)<<std::endl;
2975                                 
2976                 v3s16 blockpos = getNodeBlockPos(p);
2977                 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2978                 if(block)
2979                 {
2980                         block->setChangedFlag();
2981                 }
2982
2983                 for(core::map<u16, RemoteClient*>::Iterator
2984                         i = m_clients.getIterator();
2985                         i.atEnd()==false; i++)
2986                 {
2987                         RemoteClient *client = i.getNode()->getValue();
2988                         client->SetBlockNotSent(blockpos);
2989                 }
2990         }
2991         else if(command == TOSERVER_INVENTORY_ACTION)
2992         {
2993                 /*// Ignore inventory changes if in creative mode
2994                 if(g_settings->getBool("creative_mode") == true)
2995                 {
2996                         infostream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
2997                                         <<std::endl;
2998                         return;
2999                 }*/
3000                 // Strip command and create a stream
3001                 std::string datastring((char*)&data[2], datasize-2);
3002                 infostream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3003                 std::istringstream is(datastring, std::ios_base::binary);
3004                 // Create an action
3005                 InventoryAction *a = InventoryAction::deSerialize(is);
3006                 if(a != NULL)
3007                 {
3008                         // Create context
3009                         InventoryContext c;
3010                         c.current_player = player;
3011
3012                         /*
3013                                 Handle craftresult specially if not in creative mode
3014                         */
3015                         bool disable_action = false;
3016                         if(a->getType() == IACTION_MOVE
3017                                         && g_settings->getBool("creative_mode") == false)
3018                         {
3019                                 IMoveAction *ma = (IMoveAction*)a;
3020                                 if(ma->to_inv == "current_player" &&
3021                                                 ma->from_inv == "current_player")
3022                                 {
3023                                         InventoryList *rlist = player->inventory.getList("craftresult");
3024                                         assert(rlist);
3025                                         InventoryList *clist = player->inventory.getList("craft");
3026                                         assert(clist);
3027                                         InventoryList *mlist = player->inventory.getList("main");
3028                                         assert(mlist);
3029                                         /*
3030                                                 Craftresult is no longer preview if something
3031                                                 is moved into it
3032                                         */
3033                                         if(ma->to_list == "craftresult"
3034                                                         && ma->from_list != "craftresult")
3035                                         {
3036                                                 // If it currently is a preview, remove
3037                                                 // its contents
3038                                                 if(player->craftresult_is_preview)
3039                                                 {
3040                                                         rlist->deleteItem(0);
3041                                                 }
3042                                                 player->craftresult_is_preview = false;
3043                                         }
3044                                         /*
3045                                                 Crafting takes place if this condition is true.
3046                                         */
3047                                         if(player->craftresult_is_preview &&
3048                                                         ma->from_list == "craftresult")
3049                                         {
3050                                                 player->craftresult_is_preview = false;
3051                                                 clist->decrementMaterials(1);
3052                                                 
3053                                                 /* Print out action */
3054                                                 InventoryList *list =
3055                                                                 player->inventory.getList("craftresult");
3056                                                 assert(list);
3057                                                 InventoryItem *item = list->getItem(0);
3058                                                 std::string itemname = "NULL";
3059                                                 if(item)
3060                                                         itemname = item->getName();
3061                                                 actionstream<<player->getName()<<" crafts "
3062                                                                 <<itemname<<std::endl;
3063                                         }
3064                                         /*
3065                                                 If the craftresult is placed on itself, move it to
3066                                                 main inventory instead of doing the action
3067                                         */
3068                                         if(ma->to_list == "craftresult"
3069                                                         && ma->from_list == "craftresult")
3070                                         {
3071                                                 disable_action = true;
3072                                                 
3073                                                 InventoryItem *item1 = rlist->changeItem(0, NULL);
3074                                                 mlist->addItem(item1);
3075                                         }
3076                                 }
3077                                 // Disallow moving items if not allowed to build
3078                                 else if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3079                                 {
3080                                         return;
3081                                 }
3082                                 // if it's a locking chest, only allow the owner or server admins to move items
3083                                 else if (ma->from_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3084                                 {
3085                                         Strfnd fn(ma->from_inv);
3086                                         std::string id0 = fn.next(":");
3087                                         if(id0 == "nodemeta")
3088                                         {
3089                                                 v3s16 p;
3090                                                 p.X = stoi(fn.next(","));
3091                                                 p.Y = stoi(fn.next(","));
3092                                                 p.Z = stoi(fn.next(","));
3093                                                 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3094                                                 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3095                                                         LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3096                                                         if (lcm->getOwner() != player->getName())
3097                                                                 return;
3098                                                 }
3099                                         }
3100                                 }
3101                                 else if (ma->to_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3102                                 {
3103                                         Strfnd fn(ma->to_inv);
3104                                         std::string id0 = fn.next(":");
3105                                         if(id0 == "nodemeta")
3106                                         {
3107                                                 v3s16 p;
3108                                                 p.X = stoi(fn.next(","));
3109                                                 p.Y = stoi(fn.next(","));
3110                                                 p.Z = stoi(fn.next(","));
3111                                                 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3112                                                 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3113                                                         LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3114                                                         if (lcm->getOwner() != player->getName())
3115                                                                 return;
3116                                                 }
3117                                         }
3118                                 }
3119                         }
3120                         
3121                         if(disable_action == false)
3122                         {
3123                                 // Feed action to player inventory
3124                                 a->apply(&c, this);
3125                                 // Eat the action
3126                                 delete a;
3127                         }
3128                         else
3129                         {
3130                                 // Send inventory
3131                                 UpdateCrafting(player->peer_id);
3132                                 SendInventory(player->peer_id);
3133                         }
3134                 }
3135                 else
3136                 {
3137                         infostream<<"TOSERVER_INVENTORY_ACTION: "
3138                                         <<"InventoryAction::deSerialize() returned NULL"
3139                                         <<std::endl;
3140                 }
3141         }
3142         else if(command == TOSERVER_CHAT_MESSAGE)
3143         {
3144                 /*
3145                         u16 command
3146                         u16 length
3147                         wstring message
3148                 */
3149                 u8 buf[6];
3150                 std::string datastring((char*)&data[2], datasize-2);
3151                 std::istringstream is(datastring, std::ios_base::binary);
3152                 
3153                 // Read stuff
3154                 is.read((char*)buf, 2);
3155                 u16 len = readU16(buf);
3156                 
3157                 std::wstring message;
3158                 for(u16 i=0; i<len; i++)
3159                 {
3160                         is.read((char*)buf, 2);
3161                         message += (wchar_t)readU16(buf);
3162                 }
3163
3164                 // Get player name of this client
3165                 std::wstring name = narrow_to_wide(player->getName());
3166                 
3167                 // Line to send to players
3168                 std::wstring line;
3169                 // Whether to send to the player that sent the line
3170                 bool send_to_sender = false;
3171                 // Whether to send to other players
3172                 bool send_to_others = false;
3173                 
3174                 // Local player gets all privileges regardless of
3175                 // what's set on their account.
3176                 u64 privs = getPlayerPrivs(player);
3177
3178                 // Parse commands
3179                 if(message[0] == L'/')
3180                 {
3181                         size_t strip_size = 1;
3182                         if (message[1] == L'#') // support old-style commans
3183                                 ++strip_size;
3184                         message = message.substr(strip_size);
3185
3186                         WStrfnd f1(message);
3187                         f1.next(L" "); // Skip over /#whatever
3188                         std::wstring paramstring = f1.next(L"");
3189
3190                         ServerCommandContext *ctx = new ServerCommandContext(
3191                                 str_split(message, L' '),
3192                                 paramstring,
3193                                 this,
3194                                 m_env,
3195                                 player,
3196                                 privs);
3197
3198                         std::wstring reply(processServerCommand(ctx));
3199                         send_to_sender = ctx->flags & SEND_TO_SENDER;
3200                         send_to_others = ctx->flags & SEND_TO_OTHERS;
3201
3202                         if (ctx->flags & SEND_NO_PREFIX)
3203                                 line += reply;
3204                         else
3205                                 line += L"Server: " + reply;
3206
3207                         delete ctx;
3208
3209                 }
3210                 else
3211                 {
3212                         if(privs & PRIV_SHOUT)
3213                         {
3214                                 line += L"<";
3215                                 line += name;
3216                                 line += L"> ";
3217                                 line += message;
3218                                 send_to_others = true;
3219                         }
3220                         else
3221                         {
3222                                 line += L"Server: You are not allowed to shout";
3223                                 send_to_sender = true;
3224                         }
3225                 }
3226                 
3227                 if(line != L"")
3228                 {
3229                         if(send_to_others)
3230                                 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3231
3232                         /*
3233                                 Send the message to clients
3234                         */
3235                         for(core::map<u16, RemoteClient*>::Iterator
3236                                 i = m_clients.getIterator();
3237                                 i.atEnd() == false; i++)
3238                         {
3239                                 // Get client and check that it is valid
3240                                 RemoteClient *client = i.getNode()->getValue();
3241                                 assert(client->peer_id == i.getNode()->getKey());
3242                                 if(client->serialization_version == SER_FMT_VER_INVALID)
3243                                         continue;
3244
3245                                 // Filter recipient
3246                                 bool sender_selected = (peer_id == client->peer_id);
3247                                 if(sender_selected == true && send_to_sender == false)
3248                                         continue;
3249                                 if(sender_selected == false && send_to_others == false)
3250                                         continue;
3251
3252                                 SendChatMessage(client->peer_id, line);
3253                         }
3254                 }
3255         }
3256         else if(command == TOSERVER_DAMAGE)
3257         {
3258                 std::string datastring((char*)&data[2], datasize-2);
3259                 std::istringstream is(datastring, std::ios_base::binary);
3260                 u8 damage = readU8(is);
3261
3262                 if(g_settings->getBool("enable_damage"))
3263                 {
3264                         actionstream<<player->getName()<<" damaged by "
3265                                         <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
3266                                         <<std::endl;
3267                                 
3268                         HandlePlayerHP(player, damage);
3269                 }
3270                 else
3271                 {
3272                         SendPlayerHP(player);
3273                 }
3274         }
3275         else if(command == TOSERVER_PASSWORD)
3276         {
3277                 /*
3278                         [0] u16 TOSERVER_PASSWORD
3279                         [2] u8[28] old password
3280                         [30] u8[28] new password
3281                 */
3282
3283                 if(datasize != 2+PASSWORD_SIZE*2)
3284                         return;
3285                 /*char password[PASSWORD_SIZE];
3286                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3287                         password[i] = data[2+i];
3288                 password[PASSWORD_SIZE-1] = 0;*/
3289                 std::string oldpwd;
3290                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3291                 {
3292                         char c = data[2+i];
3293                         if(c == 0)
3294                                 break;
3295                         oldpwd += c;
3296                 }
3297                 std::string newpwd;
3298                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3299                 {
3300                         char c = data[2+PASSWORD_SIZE+i];
3301                         if(c == 0)
3302                                 break;
3303                         newpwd += c;
3304                 }
3305
3306                 infostream<<"Server: Client requests a password change from "
3307                                 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
3308
3309                 std::string playername = player->getName();
3310
3311                 if(m_authmanager.exists(playername) == false)
3312                 {
3313                         infostream<<"Server: playername not found in authmanager"<<std::endl;
3314                         // Wrong old password supplied!!
3315                         SendChatMessage(peer_id, L"playername not found in authmanager");
3316                         return;
3317                 }
3318
3319                 std::string checkpwd = m_authmanager.getPassword(playername);
3320
3321                 if(oldpwd != checkpwd)
3322                 {
3323                         infostream<<"Server: invalid old password"<<std::endl;
3324                         // Wrong old password supplied!!
3325                         SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3326                         return;
3327                 }
3328
3329                 actionstream<<player->getName()<<" changes password"<<std::endl;
3330
3331                 m_authmanager.setPassword(playername, newpwd);
3332                 
3333                 infostream<<"Server: password change successful for "<<playername
3334                                 <<std::endl;
3335                 SendChatMessage(peer_id, L"Password change successful");
3336         }
3337         else if(command == TOSERVER_PLAYERITEM)
3338         {
3339                 if (datasize < 2+2)
3340                         return;
3341
3342                 u16 item = readU16(&data[2]);
3343                 player->wieldItem(item);
3344                 SendWieldedItem(player);
3345         }
3346         else if(command == TOSERVER_RESPAWN)
3347         {
3348                 if(player->hp != 0)
3349                         return;
3350                 
3351                 RespawnPlayer(player);
3352                 
3353                 actionstream<<player->getName()<<" respawns at "
3354                                 <<PP(player->getPosition()/BS)<<std::endl;
3355         }
3356         else
3357         {
3358                 infostream<<"Server::ProcessData(): Ignoring "
3359                                 "unknown command "<<command<<std::endl;
3360         }
3361         
3362         } //try
3363         catch(SendFailedException &e)
3364         {
3365                 errorstream<<"Server::ProcessData(): SendFailedException: "
3366                                 <<"what="<<e.what()
3367                                 <<std::endl;
3368         }
3369 }
3370
3371 void Server::onMapEditEvent(MapEditEvent *event)
3372 {
3373         //infostream<<"Server::onMapEditEvent()"<<std::endl;
3374         if(m_ignore_map_edit_events)
3375                 return;
3376         MapEditEvent *e = event->clone();
3377         m_unsent_map_edit_queue.push_back(e);
3378 }
3379
3380 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3381 {
3382         if(id == "current_player")
3383         {
3384                 assert(c->current_player);
3385                 return &(c->current_player->inventory);
3386         }
3387         
3388         Strfnd fn(id);
3389         std::string id0 = fn.next(":");
3390
3391         if(id0 == "nodemeta")
3392         {
3393                 v3s16 p;
3394                 p.X = stoi(fn.next(","));
3395                 p.Y = stoi(fn.next(","));
3396                 p.Z = stoi(fn.next(","));
3397                 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3398                 if(meta)
3399                         return meta->getInventory();
3400                 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3401                                 <<"no metadata found"<<std::endl;
3402                 return NULL;
3403         }
3404
3405         infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3406         return NULL;
3407 }
3408 void Server::inventoryModified(InventoryContext *c, std::string id)
3409 {
3410         if(id == "current_player")
3411         {
3412                 assert(c->current_player);
3413                 // Send inventory
3414                 UpdateCrafting(c->current_player->peer_id);
3415                 SendInventory(c->current_player->peer_id);
3416                 return;
3417         }
3418         
3419         Strfnd fn(id);
3420         std::string id0 = fn.next(":");
3421
3422         if(id0 == "nodemeta")
3423         {
3424                 v3s16 p;
3425                 p.X = stoi(fn.next(","));
3426                 p.Y = stoi(fn.next(","));
3427                 p.Z = stoi(fn.next(","));
3428                 v3s16 blockpos = getNodeBlockPos(p);
3429
3430                 NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
3431                 if(meta)
3432                         meta->inventoryModified();
3433
3434                 for(core::map<u16, RemoteClient*>::Iterator
3435                         i = m_clients.getIterator();
3436                         i.atEnd()==false; i++)
3437                 {
3438                         RemoteClient *client = i.getNode()->getValue();
3439                         client->SetBlockNotSent(blockpos);
3440                 }
3441
3442                 return;
3443         }
3444
3445         infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3446 }
3447
3448 core::list<PlayerInfo> Server::getPlayerInfo()
3449 {
3450         DSTACK(__FUNCTION_NAME);
3451         JMutexAutoLock envlock(m_env_mutex);
3452         JMutexAutoLock conlock(m_con_mutex);
3453         
3454         core::list<PlayerInfo> list;
3455
3456         core::list<Player*> players = m_env->getPlayers();
3457         
3458         core::list<Player*>::Iterator i;
3459         for(i = players.begin();
3460                         i != players.end(); i++)
3461         {
3462                 PlayerInfo info;
3463
3464                 Player *player = *i;
3465
3466                 try{
3467                         // Copy info from connection to info struct
3468                         info.id = player->peer_id;
3469                         info.address = m_con.GetPeerAddress(player->peer_id);
3470                         info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3471                 }
3472                 catch(con::PeerNotFoundException &e)
3473                 {
3474                         // Set dummy peer info
3475                         info.id = 0;
3476                         info.address = Address(0,0,0,0,0);
3477                         info.avg_rtt = 0.0;
3478                 }
3479
3480                 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3481                 info.position = player->getPosition();
3482
3483                 list.push_back(info);
3484         }
3485
3486         return list;
3487 }
3488
3489
3490 void Server::peerAdded(con::Peer *peer)
3491 {
3492         DSTACK(__FUNCTION_NAME);
3493         infostream<<"Server::peerAdded(): peer->id="
3494                         <<peer->id<<std::endl;
3495         
3496         PeerChange c;
3497         c.type = PEER_ADDED;
3498         c.peer_id = peer->id;
3499         c.timeout = false;
3500         m_peer_change_queue.push_back(c);
3501 }
3502
3503 void Server::deletingPeer(con::Peer *peer, bool timeout)
3504 {
3505         DSTACK(__FUNCTION_NAME);
3506         infostream<<"Server::deletingPeer(): peer->id="
3507                         <<peer->id<<", timeout="<<timeout<<std::endl;
3508         
3509         PeerChange c;
3510         c.type = PEER_REMOVED;
3511         c.peer_id = peer->id;
3512         c.timeout = timeout;
3513         m_peer_change_queue.push_back(c);
3514 }
3515
3516 /*
3517         Static send methods
3518 */
3519
3520 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3521 {
3522         DSTACK(__FUNCTION_NAME);
3523         std::ostringstream os(std::ios_base::binary);
3524
3525         writeU16(os, TOCLIENT_HP);
3526         writeU8(os, hp);
3527
3528         // Make data buffer
3529         std::string s = os.str();
3530         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3531         // Send as reliable
3532         con.Send(peer_id, 0, data, true);
3533 }
3534
3535 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3536                 const std::wstring &reason)
3537 {
3538         DSTACK(__FUNCTION_NAME);
3539         std::ostringstream os(std::ios_base::binary);
3540
3541         writeU16(os, TOCLIENT_ACCESS_DENIED);
3542         os<<serializeWideString(reason);
3543
3544         // Make data buffer
3545         std::string s = os.str();
3546         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3547         // Send as reliable
3548         con.Send(peer_id, 0, data, true);
3549 }
3550
3551 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3552                 bool set_camera_point_target, v3f camera_point_target)
3553 {
3554         DSTACK(__FUNCTION_NAME);
3555         std::ostringstream os(std::ios_base::binary);
3556
3557         writeU16(os, TOCLIENT_DEATHSCREEN);
3558         writeU8(os, set_camera_point_target);
3559         writeV3F1000(os, camera_point_target);
3560
3561         // Make data buffer
3562         std::string s = os.str();
3563         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3564         // Send as reliable
3565         con.Send(peer_id, 0, data, true);
3566 }
3567
3568 /*
3569         Non-static send methods
3570 */
3571
3572 void Server::SendObjectData(float dtime)
3573 {
3574         DSTACK(__FUNCTION_NAME);
3575
3576         core::map<v3s16, bool> stepped_blocks;
3577         
3578         for(core::map<u16, RemoteClient*>::Iterator
3579                 i = m_clients.getIterator();
3580                 i.atEnd() == false; i++)
3581         {
3582                 u16 peer_id = i.getNode()->getKey();
3583                 RemoteClient *client = i.getNode()->getValue();
3584                 assert(client->peer_id == peer_id);
3585                 
3586                 if(client->serialization_version == SER_FMT_VER_INVALID)
3587                         continue;
3588                 
3589                 client->SendObjectData(this, dtime, stepped_blocks);
3590         }
3591 }
3592
3593 void Server::SendPlayerInfos()
3594 {
3595         DSTACK(__FUNCTION_NAME);
3596
3597         //JMutexAutoLock envlock(m_env_mutex);
3598         
3599         // Get connected players
3600         core::list<Player*> players = m_env->getPlayers(true);
3601         
3602         u32 player_count = players.getSize();
3603         u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3604
3605         SharedBuffer<u8> data(datasize);
3606         writeU16(&data[0], TOCLIENT_PLAYERINFO);
3607         
3608         u32 start = 2;
3609         core::list<Player*>::Iterator i;
3610         for(i = players.begin();
3611                         i != players.end(); i++)
3612         {
3613                 Player *player = *i;
3614
3615                 /*infostream<<"Server sending player info for player with "
3616                                 "peer_id="<<player->peer_id<<std::endl;*/
3617                 
3618                 writeU16(&data[start], player->peer_id);
3619                 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3620                 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3621                 start += 2+PLAYERNAME_SIZE;
3622         }
3623
3624         //JMutexAutoLock conlock(m_con_mutex);
3625
3626         // Send as reliable
3627         m_con.SendToAll(0, data, true);
3628 }
3629
3630 void Server::SendInventory(u16 peer_id)
3631 {
3632         DSTACK(__FUNCTION_NAME);
3633         
3634         Player* player = m_env->getPlayer(peer_id);
3635         assert(player);
3636
3637         /*
3638                 Serialize it
3639         */
3640
3641         std::ostringstream os;
3642         //os.imbue(std::locale("C"));
3643
3644         player->inventory.serialize(os);
3645
3646         std::string s = os.str();
3647         
3648         SharedBuffer<u8> data(s.size()+2);
3649         writeU16(&data[0], TOCLIENT_INVENTORY);
3650         memcpy(&data[2], s.c_str(), s.size());
3651         
3652         // Send as reliable
3653         m_con.Send(peer_id, 0, data, true);
3654 }
3655
3656 std::string getWieldedItemString(const Player *player)
3657 {
3658         const InventoryItem *item = player->getWieldItem();
3659         if (item == NULL)
3660                 return std::string("");
3661         std::ostringstream os(std::ios_base::binary);
3662         item->serialize(os);
3663         return os.str();
3664 }
3665
3666 void Server::SendWieldedItem(const Player* player)
3667 {
3668         DSTACK(__FUNCTION_NAME);
3669
3670         assert(player);
3671
3672         std::ostringstream os(std::ios_base::binary);
3673
3674         writeU16(os, TOCLIENT_PLAYERITEM);
3675         writeU16(os, 1);
3676         writeU16(os, player->peer_id);
3677         os<<serializeString(getWieldedItemString(player));
3678
3679         // Make data buffer
3680         std::string s = os.str();
3681         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3682
3683         m_con.SendToAll(0, data, true);
3684 }
3685
3686 void Server::SendPlayerItems()
3687 {
3688         DSTACK(__FUNCTION_NAME);
3689
3690         std::ostringstream os(std::ios_base::binary);
3691         core::list<Player *> players = m_env->getPlayers(true);
3692
3693         writeU16(os, TOCLIENT_PLAYERITEM);
3694         writeU16(os, players.size());
3695         core::list<Player *>::Iterator i;
3696         for(i = players.begin(); i != players.end(); ++i)
3697         {
3698                 Player *p = *i;
3699                 writeU16(os, p->peer_id);
3700                 os<<serializeString(getWieldedItemString(p));
3701         }
3702
3703         // Make data buffer
3704         std::string s = os.str();
3705         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3706
3707         m_con.SendToAll(0, data, true);
3708 }
3709
3710 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3711 {
3712         DSTACK(__FUNCTION_NAME);
3713         
3714         std::ostringstream os(std::ios_base::binary);
3715         u8 buf[12];
3716         
3717         // Write command
3718         writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3719         os.write((char*)buf, 2);
3720         
3721         // Write length
3722         writeU16(buf, message.size());
3723         os.write((char*)buf, 2);
3724         
3725         // Write string
3726         for(u32 i=0; i<message.size(); i++)
3727         {
3728                 u16 w = message[i];
3729                 writeU16(buf, w);
3730                 os.write((char*)buf, 2);
3731         }
3732         
3733         // Make data buffer
3734         std::string s = os.str();
3735         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3736         // Send as reliable
3737         m_con.Send(peer_id, 0, data, true);
3738 }
3739
3740 void Server::BroadcastChatMessage(const std::wstring &message)
3741 {
3742         for(core::map<u16, RemoteClient*>::Iterator
3743                 i = m_clients.getIterator();
3744                 i.atEnd() == false; i++)
3745         {
3746                 // Get client and check that it is valid
3747                 RemoteClient *client = i.getNode()->getValue();
3748                 assert(client->peer_id == i.getNode()->getKey());
3749                 if(client->serialization_version == SER_FMT_VER_INVALID)
3750                         continue;
3751
3752                 SendChatMessage(client->peer_id, message);
3753         }
3754 }
3755
3756 void Server::SendPlayerHP(Player *player)
3757 {
3758         SendHP(m_con, player->peer_id, player->hp);
3759 }
3760
3761 void Server::SendMovePlayer(Player *player)
3762 {
3763         DSTACK(__FUNCTION_NAME);
3764         std::ostringstream os(std::ios_base::binary);
3765
3766         writeU16(os, TOCLIENT_MOVE_PLAYER);
3767         writeV3F1000(os, player->getPosition());
3768         writeF1000(os, player->getPitch());
3769         writeF1000(os, player->getYaw());
3770         
3771         {
3772                 v3f pos = player->getPosition();
3773                 f32 pitch = player->getPitch();
3774                 f32 yaw = player->getYaw();
3775                 infostream<<"Server sending TOCLIENT_MOVE_PLAYER"
3776                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3777                                 <<" pitch="<<pitch
3778                                 <<" yaw="<<yaw
3779                                 <<std::endl;
3780         }
3781
3782         // Make data buffer
3783         std::string s = os.str();
3784         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3785         // Send as reliable
3786         m_con.Send(player->peer_id, 0, data, true);
3787 }
3788
3789 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3790         core::list<u16> *far_players, float far_d_nodes)
3791 {
3792         float maxd = far_d_nodes*BS;
3793         v3f p_f = intToFloat(p, BS);
3794
3795         // Create packet
3796         u32 replysize = 8;
3797         SharedBuffer<u8> reply(replysize);
3798         writeU16(&reply[0], TOCLIENT_REMOVENODE);
3799         writeS16(&reply[2], p.X);
3800         writeS16(&reply[4], p.Y);
3801         writeS16(&reply[6], p.Z);
3802
3803         for(core::map<u16, RemoteClient*>::Iterator
3804                 i = m_clients.getIterator();
3805                 i.atEnd() == false; i++)
3806         {
3807                 // Get client and check that it is valid
3808                 RemoteClient *client = i.getNode()->getValue();
3809                 assert(client->peer_id == i.getNode()->getKey());
3810                 if(client->serialization_version == SER_FMT_VER_INVALID)
3811                         continue;
3812
3813                 // Don't send if it's the same one
3814                 if(client->peer_id == ignore_id)
3815                         continue;
3816                 
3817                 if(far_players)
3818                 {
3819                         // Get player
3820                         Player *player = m_env->getPlayer(client->peer_id);
3821                         if(player)
3822                         {
3823                                 // If player is far away, only set modified blocks not sent
3824                                 v3f player_pos = player->getPosition();
3825                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3826                                 {
3827                                         far_players->push_back(client->peer_id);
3828                                         continue;
3829                                 }
3830                         }
3831                 }
3832
3833                 // Send as reliable
3834                 m_con.Send(client->peer_id, 0, reply, true);
3835         }
3836 }
3837
3838 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3839                 core::list<u16> *far_players, float far_d_nodes)
3840 {
3841         float maxd = far_d_nodes*BS;
3842         v3f p_f = intToFloat(p, BS);
3843
3844         for(core::map<u16, RemoteClient*>::Iterator
3845                 i = m_clients.getIterator();
3846                 i.atEnd() == false; i++)
3847         {
3848                 // Get client and check that it is valid
3849                 RemoteClient *client = i.getNode()->getValue();
3850                 assert(client->peer_id == i.getNode()->getKey());
3851                 if(client->serialization_version == SER_FMT_VER_INVALID)
3852                         continue;
3853
3854                 // Don't send if it's the same one
3855                 if(client->peer_id == ignore_id)
3856                         continue;
3857
3858                 if(far_players)
3859                 {
3860                         // Get player
3861                         Player *player = m_env->getPlayer(client->peer_id);
3862                         if(player)
3863                         {
3864                                 // If player is far away, only set modified blocks not sent
3865                                 v3f player_pos = player->getPosition();
3866                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3867                                 {
3868                                         far_players->push_back(client->peer_id);
3869                                         continue;
3870                                 }
3871                         }
3872                 }
3873
3874                 // Create packet
3875                 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3876                 SharedBuffer<u8> reply(replysize);
3877                 writeU16(&reply[0], TOCLIENT_ADDNODE);
3878                 writeS16(&reply[2], p.X);
3879                 writeS16(&reply[4], p.Y);
3880                 writeS16(&reply[6], p.Z);
3881                 n.serialize(&reply[8], client->serialization_version);
3882
3883                 // Send as reliable
3884                 m_con.Send(client->peer_id, 0, reply, true);
3885         }
3886 }
3887
3888 void Server::setBlockNotSent(v3s16 p)
3889 {
3890         for(core::map<u16, RemoteClient*>::Iterator
3891                 i = m_clients.getIterator();
3892                 i.atEnd()==false; i++)
3893         {
3894                 RemoteClient *client = i.getNode()->getValue();
3895                 client->SetBlockNotSent(p);
3896         }
3897 }
3898
3899 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3900 {
3901         DSTACK(__FUNCTION_NAME);
3902
3903         v3s16 p = block->getPos();
3904         
3905 #if 0
3906         // Analyze it a bit
3907         bool completely_air = true;
3908         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3909         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3910         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3911         {
3912                 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3913                 {
3914                         completely_air = false;
3915                         x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3916                 }
3917         }
3918
3919         // Print result
3920         infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3921         if(completely_air)
3922                 infostream<<"[completely air] ";
3923         infostream<<std::endl;
3924 #endif
3925
3926         /*
3927                 Create a packet with the block in the right format
3928         */
3929         
3930         std::ostringstream os(std::ios_base::binary);
3931         block->serialize(os, ver);
3932         std::string s = os.str();
3933         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3934
3935         u32 replysize = 8 + blockdata.getSize();
3936         SharedBuffer<u8> reply(replysize);
3937         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3938         writeS16(&reply[2], p.X);
3939         writeS16(&reply[4], p.Y);
3940         writeS16(&reply[6], p.Z);
3941         memcpy(&reply[8], *blockdata, blockdata.getSize());
3942
3943         /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3944                         <<":  \tpacket size: "<<replysize<<std::endl;*/
3945         
3946         /*
3947                 Send packet
3948         */
3949         m_con.Send(peer_id, 1, reply, true);
3950 }
3951
3952 void Server::SendBlocks(float dtime)
3953 {
3954         DSTACK(__FUNCTION_NAME);
3955
3956         JMutexAutoLock envlock(m_env_mutex);
3957         JMutexAutoLock conlock(m_con_mutex);
3958
3959         //TimeTaker timer("Server::SendBlocks");
3960
3961         core::array<PrioritySortedBlockTransfer> queue;
3962
3963         s32 total_sending = 0;
3964         
3965         {
3966                 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3967
3968                 for(core::map<u16, RemoteClient*>::Iterator
3969                         i = m_clients.getIterator();
3970                         i.atEnd() == false; i++)
3971                 {
3972                         RemoteClient *client = i.getNode()->getValue();
3973                         assert(client->peer_id == i.getNode()->getKey());
3974
3975                         total_sending += client->SendingCount();
3976                         
3977                         if(client->serialization_version == SER_FMT_VER_INVALID)
3978                                 continue;
3979                         
3980                         client->GetNextBlocks(this, dtime, queue);
3981                 }
3982         }
3983
3984         // Sort.
3985         // Lowest priority number comes first.
3986         // Lowest is most important.
3987         queue.sort();
3988
3989         for(u32 i=0; i<queue.size(); i++)
3990         {
3991                 //TODO: Calculate limit dynamically
3992                 if(total_sending >= g_settings->getS32
3993                                 ("max_simultaneous_block_sends_server_total"))
3994                         break;
3995                 
3996                 PrioritySortedBlockTransfer q = queue[i];
3997
3998                 MapBlock *block = NULL;
3999                 try
4000                 {
4001                         block = m_env->getMap().getBlockNoCreate(q.pos);
4002                 }
4003                 catch(InvalidPositionException &e)
4004                 {
4005                         continue;
4006                 }
4007
4008                 RemoteClient *client = getClient(q.peer_id);
4009
4010                 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4011
4012                 client->SentBlock(q.pos);
4013
4014                 total_sending++;
4015         }
4016 }
4017
4018 /*
4019         Something random
4020 */
4021
4022 void Server::HandlePlayerHP(Player *player, s16 damage)
4023 {
4024         if(player->hp > damage)
4025         {
4026                 player->hp -= damage;
4027                 SendPlayerHP(player);
4028         }
4029         else
4030         {
4031                 infostream<<"Server::HandlePlayerHP(): Player "
4032                                 <<player->getName()<<" dies"<<std::endl;
4033                 
4034                 player->hp = 0;
4035                 
4036                 //TODO: Throw items around
4037                 
4038                 // Handle players that are not connected
4039                 if(player->peer_id == PEER_ID_INEXISTENT){
4040                         RespawnPlayer(player);
4041                         return;
4042                 }
4043
4044                 SendPlayerHP(player);
4045                 
4046                 RemoteClient *client = getClient(player->peer_id);
4047                 if(client->net_proto_version >= 3)
4048                 {
4049                         SendDeathscreen(m_con, player->peer_id, false, v3f(0,0,0));
4050                 }
4051                 else
4052                 {
4053                         RespawnPlayer(player);
4054                 }
4055         }
4056 }
4057
4058 void Server::RespawnPlayer(Player *player)
4059 {
4060         v3f pos = findSpawnPos(m_env->getServerMap());
4061         player->setPosition(pos);
4062         player->hp = 20;
4063         SendMovePlayer(player);
4064         SendPlayerHP(player);
4065 }
4066
4067 void Server::UpdateCrafting(u16 peer_id)
4068 {
4069         DSTACK(__FUNCTION_NAME);
4070         
4071         Player* player = m_env->getPlayer(peer_id);
4072         assert(player);
4073
4074         /*
4075                 Calculate crafting stuff
4076         */
4077         if(g_settings->getBool("creative_mode") == false)
4078         {
4079                 InventoryList *clist = player->inventory.getList("craft");
4080                 InventoryList *rlist = player->inventory.getList("craftresult");
4081
4082                 if(rlist && rlist->getUsedSlots() == 0)
4083                         player->craftresult_is_preview = true;
4084
4085                 if(rlist && player->craftresult_is_preview)
4086                 {
4087                         rlist->clearItems();
4088                 }
4089                 if(clist && rlist && player->craftresult_is_preview)
4090                 {
4091                         InventoryItem *items[9];
4092                         for(u16 i=0; i<9; i++)
4093                         {
4094                                 items[i] = clist->getItem(i);
4095                         }
4096                         
4097                         // Get result of crafting grid
4098                         InventoryItem *result = craft_get_result(items);
4099                         if(result)
4100                                 rlist->addItem(result);
4101                 }
4102         
4103         } // if creative_mode == false
4104 }
4105
4106 RemoteClient* Server::getClient(u16 peer_id)
4107 {
4108         DSTACK(__FUNCTION_NAME);
4109         //JMutexAutoLock lock(m_con_mutex);
4110         core::map<u16, RemoteClient*>::Node *n;
4111         n = m_clients.find(peer_id);
4112         // A client should exist for all peers
4113         assert(n != NULL);
4114         return n->getValue();
4115 }
4116
4117 std::wstring Server::getStatusString()
4118 {
4119         std::wostringstream os(std::ios_base::binary);
4120         os<<L"# Server: ";
4121         // Version
4122         os<<L"version="<<narrow_to_wide(VERSION_STRING);
4123         // Uptime
4124         os<<L", uptime="<<m_uptime.get();
4125         // Information about clients
4126         os<<L", clients={";
4127         for(core::map<u16, RemoteClient*>::Iterator
4128                 i = m_clients.getIterator();
4129                 i.atEnd() == false; i++)
4130         {
4131                 // Get client and check that it is valid
4132                 RemoteClient *client = i.getNode()->getValue();
4133                 assert(client->peer_id == i.getNode()->getKey());
4134                 if(client->serialization_version == SER_FMT_VER_INVALID)
4135                         continue;
4136                 // Get player
4137                 Player *player = m_env->getPlayer(client->peer_id);
4138                 // Get name of player
4139                 std::wstring name = L"unknown";
4140                 if(player != NULL)
4141                         name = narrow_to_wide(player->getName());
4142                 // Add name to information string
4143                 os<<name<<L",";
4144         }
4145         os<<L"}";
4146         if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4147                 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4148         if(g_settings->get("motd") != "")
4149                 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4150         return os.str();
4151 }
4152
4153 // Saves g_settings to configpath given at initialization
4154 void Server::saveConfig()
4155 {
4156         if(m_configpath != "")
4157                 g_settings->updateConfigFile(m_configpath.c_str());
4158 }
4159
4160 void Server::notifyPlayer(const char *name, const std::wstring msg)
4161 {
4162         Player *player = m_env->getPlayer(name);
4163         if(!player)
4164                 return;
4165         SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4166 }
4167
4168 void Server::notifyPlayers(const std::wstring msg)
4169 {
4170         BroadcastChatMessage(msg);
4171 }
4172
4173 v3f findSpawnPos(ServerMap &map)
4174 {
4175         //return v3f(50,50,50)*BS;
4176
4177         v3s16 nodepos;
4178         
4179 #if 0
4180         nodepos = v2s16(0,0);
4181         groundheight = 20;
4182 #endif
4183
4184 #if 1
4185         // Try to find a good place a few times
4186         for(s32 i=0; i<1000; i++)
4187         {
4188                 s32 range = 1 + i;
4189                 // We're going to try to throw the player to this position
4190                 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4191                                 -range + (myrand()%(range*2)));
4192                 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4193                 // Get ground height at point (fallbacks to heightmap function)
4194                 s16 groundheight = map.findGroundLevel(nodepos2d);
4195                 // Don't go underwater
4196                 if(groundheight < WATER_LEVEL)
4197                 {
4198                         //infostream<<"-> Underwater"<<std::endl;
4199                         continue;
4200                 }
4201                 // Don't go to high places
4202                 if(groundheight > WATER_LEVEL + 4)
4203                 {
4204                         //infostream<<"-> Underwater"<<std::endl;
4205                         continue;
4206                 }
4207                 
4208                 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4209                 bool is_good = false;
4210                 s32 air_count = 0;
4211                 for(s32 i=0; i<10; i++){
4212                         v3s16 blockpos = getNodeBlockPos(nodepos);
4213                         map.emergeBlock(blockpos, true);
4214                         MapNode n = map.getNodeNoEx(nodepos);
4215                         if(n.getContent() == CONTENT_AIR){
4216                                 air_count++;
4217                                 if(air_count >= 2){
4218                                         is_good = true;
4219                                         nodepos.Y -= 1;
4220                                         break;
4221                                 }
4222                         }
4223                         nodepos.Y++;
4224                 }
4225                 if(is_good){
4226                         // Found a good place
4227                         //infostream<<"Searched through "<<i<<" places."<<std::endl;
4228                         break;
4229                 }
4230         }
4231 #endif
4232         
4233         return intToFloat(nodepos, BS);
4234 }
4235
4236 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4237 {
4238         /*
4239                 Try to get an existing player
4240         */
4241         Player *player = m_env->getPlayer(name);
4242         if(player != NULL)
4243         {
4244                 // If player is already connected, cancel
4245                 if(player->peer_id != 0)
4246                 {
4247                         infostream<<"emergePlayer(): Player already connected"<<std::endl;
4248                         return NULL;
4249                 }
4250
4251                 // Got one.
4252                 player->peer_id = peer_id;
4253                 
4254                 // Reset inventory to creative if in creative mode
4255                 if(g_settings->getBool("creative_mode"))
4256                 {
4257                         // Warning: double code below
4258                         // Backup actual inventory
4259                         player->inventory_backup = new Inventory();
4260                         *(player->inventory_backup) = player->inventory;
4261                         // Set creative inventory
4262                         craft_set_creative_inventory(player);
4263                 }
4264
4265                 return player;
4266         }
4267
4268         /*
4269                 If player with the wanted peer_id already exists, cancel.
4270         */
4271         if(m_env->getPlayer(peer_id) != NULL)
4272         {
4273                 infostream<<"emergePlayer(): Player with wrong name but same"
4274                                 " peer_id already exists"<<std::endl;
4275                 return NULL;
4276         }
4277         
4278         /*
4279                 Create a new player
4280         */
4281         {
4282                 player = new ServerRemotePlayer();
4283                 //player->peer_id = c.peer_id;
4284                 //player->peer_id = PEER_ID_INEXISTENT;
4285                 player->peer_id = peer_id;
4286                 player->updateName(name);
4287                 m_authmanager.add(name);
4288                 m_authmanager.setPassword(name, password);
4289                 m_authmanager.setPrivs(name,
4290                                 stringToPrivs(g_settings->get("default_privs")));
4291
4292                 /*
4293                         Set player position
4294                 */
4295                 
4296                 infostream<<"Server: Finding spawn place for player \""
4297                                 <<player->getName()<<"\""<<std::endl;
4298
4299                 v3f pos = findSpawnPos(m_env->getServerMap());
4300
4301                 player->setPosition(pos);
4302
4303                 /*
4304                         Add player to environment
4305                 */
4306
4307                 m_env->addPlayer(player);
4308
4309                 /*
4310                         Add stuff to inventory
4311                 */
4312                 
4313                 if(g_settings->getBool("creative_mode"))
4314                 {
4315                         // Warning: double code above
4316                         // Backup actual inventory
4317                         player->inventory_backup = new Inventory();
4318                         *(player->inventory_backup) = player->inventory;
4319                         // Set creative inventory
4320                         craft_set_creative_inventory(player);
4321                 }
4322                 else if(g_settings->getBool("give_initial_stuff"))
4323                 {
4324                         craft_give_initial_stuff(player);
4325                 }
4326
4327                 return player;
4328                 
4329         } // create new player
4330 }
4331
4332 void Server::handlePeerChange(PeerChange &c)
4333 {
4334         JMutexAutoLock envlock(m_env_mutex);
4335         JMutexAutoLock conlock(m_con_mutex);
4336         
4337         if(c.type == PEER_ADDED)
4338         {
4339                 /*
4340                         Add
4341                 */
4342
4343                 // Error check
4344                 core::map<u16, RemoteClient*>::Node *n;
4345                 n = m_clients.find(c.peer_id);
4346                 // The client shouldn't already exist
4347                 assert(n == NULL);
4348
4349                 // Create client
4350                 RemoteClient *client = new RemoteClient();
4351                 client->peer_id = c.peer_id;
4352                 m_clients.insert(client->peer_id, client);
4353
4354         } // PEER_ADDED
4355         else if(c.type == PEER_REMOVED)
4356         {
4357                 /*
4358                         Delete
4359                 */
4360
4361                 // Error check
4362                 core::map<u16, RemoteClient*>::Node *n;
4363                 n = m_clients.find(c.peer_id);
4364                 // The client should exist
4365                 assert(n != NULL);
4366                 
4367                 /*
4368                         Mark objects to be not known by the client
4369                 */
4370                 RemoteClient *client = n->getValue();
4371                 // Handle objects
4372                 for(core::map<u16, bool>::Iterator
4373                                 i = client->m_known_objects.getIterator();
4374                                 i.atEnd()==false; i++)
4375                 {
4376                         // Get object
4377                         u16 id = i.getNode()->getKey();
4378                         ServerActiveObject* obj = m_env->getActiveObject(id);
4379                         
4380                         if(obj && obj->m_known_by_count > 0)
4381                                 obj->m_known_by_count--;
4382                 }
4383
4384                 // Collect information about leaving in chat
4385                 std::wstring message;
4386                 {
4387                         Player *player = m_env->getPlayer(c.peer_id);
4388                         if(player != NULL)
4389                         {
4390                                 std::wstring name = narrow_to_wide(player->getName());
4391                                 message += L"*** ";
4392                                 message += name;
4393                                 message += L" left game";
4394                                 if(c.timeout)
4395                                         message += L" (timed out)";
4396                         }
4397                 }
4398
4399                 /*// Delete player
4400                 {
4401                         m_env->removePlayer(c.peer_id);
4402                 }*/
4403
4404                 // Set player client disconnected
4405                 {
4406                         Player *player = m_env->getPlayer(c.peer_id);
4407                         if(player != NULL)
4408                                 player->peer_id = 0;
4409                         
4410                         /*
4411                                 Print out action
4412                         */
4413                         if(player != NULL)
4414                         {
4415                                 std::ostringstream os(std::ios_base::binary);
4416                                 for(core::map<u16, RemoteClient*>::Iterator
4417                                         i = m_clients.getIterator();
4418                                         i.atEnd() == false; i++)
4419                                 {
4420                                         RemoteClient *client = i.getNode()->getValue();
4421                                         assert(client->peer_id == i.getNode()->getKey());
4422                                         if(client->serialization_version == SER_FMT_VER_INVALID)
4423                                                 continue;
4424                                         // Get player
4425                                         Player *player = m_env->getPlayer(client->peer_id);
4426                                         if(!player)
4427                                                 continue;
4428                                         // Get name of player
4429                                         os<<player->getName()<<" ";
4430                                 }
4431
4432                                 actionstream<<player->getName()<<" "
4433                                                 <<(c.timeout?"times out.":"leaves game.")
4434                                                 <<" List of players: "
4435                                                 <<os.str()<<std::endl;
4436                         }
4437                 }
4438                 
4439                 // Delete client
4440                 delete m_clients[c.peer_id];
4441                 m_clients.remove(c.peer_id);
4442
4443                 // Send player info to all remaining clients
4444                 SendPlayerInfos();
4445                 
4446                 // Send leave chat message to all remaining clients
4447                 BroadcastChatMessage(message);
4448                 
4449         } // PEER_REMOVED
4450         else
4451         {
4452                 assert(0);
4453         }
4454 }
4455
4456 void Server::handlePeerChanges()
4457 {
4458         while(m_peer_change_queue.size() > 0)
4459         {
4460                 PeerChange c = m_peer_change_queue.pop_front();
4461
4462                 infostream<<"Server: Handling peer change: "
4463                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4464                                 <<std::endl;
4465
4466                 handlePeerChange(c);
4467         }
4468 }
4469
4470 u64 Server::getPlayerPrivs(Player *player)
4471 {
4472         if(player==NULL)
4473                 return 0;
4474         std::string playername = player->getName();
4475         // Local player gets all privileges regardless of
4476         // what's set on their account.
4477         if(g_settings->get("name") == playername)
4478         {
4479                 return PRIV_ALL;
4480         }
4481         else
4482         {
4483                 return getPlayerAuthPrivs(playername);
4484         }
4485 }
4486
4487 void dedicated_server_loop(Server &server, bool &kill)
4488 {
4489         DSTACK(__FUNCTION_NAME);
4490         
4491         infostream<<DTIME<<std::endl;
4492         infostream<<"========================"<<std::endl;
4493         infostream<<"Running dedicated server"<<std::endl;
4494         infostream<<"========================"<<std::endl;
4495         infostream<<std::endl;
4496
4497         IntervalLimiter m_profiler_interval;
4498
4499         for(;;)
4500         {
4501                 // This is kind of a hack but can be done like this
4502                 // because server.step() is very light
4503                 {
4504                         ScopeProfiler sp(g_profiler, "dedicated server sleep");
4505                         sleep_ms(30);
4506                 }
4507                 server.step(0.030);
4508
4509                 if(server.getShutdownRequested() || kill)
4510                 {
4511                         infostream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4512                         break;
4513                 }
4514
4515                 /*
4516                         Profiler
4517                 */
4518                 float profiler_print_interval =
4519                                 g_settings->getFloat("profiler_print_interval");
4520                 if(profiler_print_interval != 0)
4521                 {
4522                         if(m_profiler_interval.step(0.030, profiler_print_interval))
4523                         {
4524                                 infostream<<"Profiler:"<<std::endl;
4525                                 g_profiler->print(infostream);
4526                                 g_profiler->clear();
4527                         }
4528                 }
4529                 
4530                 /*
4531                         Player info
4532                 */
4533                 static int counter = 0;
4534                 counter--;
4535                 if(counter <= 0)
4536                 {
4537                         counter = 10;
4538
4539                         core::list<PlayerInfo> list = server.getPlayerInfo();
4540                         core::list<PlayerInfo>::Iterator i;
4541                         static u32 sum_old = 0;
4542                         u32 sum = PIChecksum(list);
4543                         if(sum != sum_old)
4544                         {
4545                                 infostream<<DTIME<<"Player info:"<<std::endl;
4546                                 for(i=list.begin(); i!=list.end(); i++)
4547                                 {
4548                                         i->PrintLine(&infostream);
4549                                 }
4550                         }
4551                         sum_old = sum;
4552                 }
4553         }
4554 }
4555
4556