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