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