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