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