]> git.lizzy.rs Git - minetest.git/blob - src/server.cpp
reorganized a lot of stuff and modified mapgen and objects slightly while doing it
[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                                 // Save only changed parts
1835                                 m_env.getMap().save(true);
1836
1837                                 // Delete unused sectors
1838                                 u32 deleted_count = m_env.getMap().unloadUnusedData(
1839                                                 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1840                                 if(deleted_count > 0)
1841                                 {
1842                                         dout_server<<"Server: Unloaded "<<deleted_count
1843                                                         <<" sectors from memory"<<std::endl;
1844                                 }
1845
1846                                 // Save players
1847                                 m_env.serializePlayers(m_mapsavedir);
1848                                 
1849                                 // Save environment metadata
1850                                 m_env.saveMeta(m_mapsavedir);
1851                         }
1852                 }
1853         }
1854 }
1855
1856 void Server::Receive()
1857 {
1858         DSTACK(__FUNCTION_NAME);
1859         u32 data_maxsize = 10000;
1860         Buffer<u8> data(data_maxsize);
1861         u16 peer_id;
1862         u32 datasize;
1863         try{
1864                 {
1865                         JMutexAutoLock conlock(m_con_mutex);
1866                         datasize = m_con.Receive(peer_id, *data, data_maxsize);
1867                 }
1868
1869                 // This has to be called so that the client list gets synced
1870                 // with the peer list of the connection
1871                 handlePeerChanges();
1872
1873                 ProcessData(*data, datasize, peer_id);
1874         }
1875         catch(con::InvalidIncomingDataException &e)
1876         {
1877                 derr_server<<"Server::Receive(): "
1878                                 "InvalidIncomingDataException: what()="
1879                                 <<e.what()<<std::endl;
1880         }
1881         catch(con::PeerNotFoundException &e)
1882         {
1883                 //NOTE: This is not needed anymore
1884                 
1885                 // The peer has been disconnected.
1886                 // Find the associated player and remove it.
1887
1888                 /*JMutexAutoLock envlock(m_env_mutex);
1889
1890                 dout_server<<"ServerThread: peer_id="<<peer_id
1891                                 <<" has apparently closed connection. "
1892                                 <<"Removing player."<<std::endl;
1893
1894                 m_env.removePlayer(peer_id);*/
1895         }
1896 }
1897
1898 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1899 {
1900         DSTACK(__FUNCTION_NAME);
1901         // Environment is locked first.
1902         JMutexAutoLock envlock(m_env_mutex);
1903         JMutexAutoLock conlock(m_con_mutex);
1904         
1905         con::Peer *peer;
1906         try{
1907                 peer = m_con.GetPeer(peer_id);
1908         }
1909         catch(con::PeerNotFoundException &e)
1910         {
1911                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1912                                 <<peer_id<<" not found"<<std::endl;
1913                 return;
1914         }
1915         
1916         u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1917
1918         try
1919         {
1920
1921         if(datasize < 2)
1922                 return;
1923
1924         ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1925         
1926         if(command == TOSERVER_INIT)
1927         {
1928                 // [0] u16 TOSERVER_INIT
1929                 // [2] u8 SER_FMT_VER_HIGHEST
1930                 // [3] u8[20] player_name
1931                 // [23] u8[28] password <--- can be sent without this, from old versions
1932
1933                 if(datasize < 2+1+PLAYERNAME_SIZE)
1934                         return;
1935
1936                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1937                                 <<peer->id<<std::endl;
1938
1939                 // First byte after command is maximum supported
1940                 // serialization version
1941                 u8 client_max = data[2];
1942                 u8 our_max = SER_FMT_VER_HIGHEST;
1943                 // Use the highest version supported by both
1944                 u8 deployed = core::min_(client_max, our_max);
1945                 // If it's lower than the lowest supported, give up.
1946                 if(deployed < SER_FMT_VER_LOWEST)
1947                         deployed = SER_FMT_VER_INVALID;
1948
1949                 //peer->serialization_version = deployed;
1950                 getClient(peer->id)->pending_serialization_version = deployed;
1951
1952                 if(deployed == SER_FMT_VER_INVALID)
1953                 {
1954                         derr_server<<DTIME<<"Server: Cannot negotiate "
1955                                         "serialization version with peer "
1956                                         <<peer_id<<std::endl;
1957                         return;
1958                 }
1959
1960                 /*
1961                         Set up player
1962                 */
1963                 
1964                 // Get player name
1965                 char playername[PLAYERNAME_SIZE];
1966                 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1967                 {
1968                         playername[i] = data[3+i];
1969                 }
1970                 playername[PLAYERNAME_SIZE-1] = 0;
1971                 
1972                 if(playername[0]=='\0')
1973                 {
1974                         derr_server<<DTIME<<"Server: Player has empty name"<<std::endl;
1975                         SendAccessDenied(m_con, peer_id,
1976                                         L"Empty name");
1977                         return;
1978                 }
1979
1980                 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1981                 {
1982                         derr_server<<DTIME<<"Server: Player has invalid name"<<std::endl;
1983                         SendAccessDenied(m_con, peer_id,
1984                                         L"Name contains unallowed characters");
1985                         return;
1986                 }
1987
1988                 // Get password
1989                 char password[PASSWORD_SIZE];
1990                 if(datasize == 2+1+PLAYERNAME_SIZE)
1991                 {
1992                         // old version - assume blank password
1993                         password[0] = 0;
1994                 }
1995                 else
1996                 {
1997                                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1998                                 {
1999                                         password[i] = data[23+i];
2000                                 }
2001                                 password[PASSWORD_SIZE-1] = 0;
2002                 }
2003                 
2004                 std::string checkpwd;
2005                 if(m_authmanager.exists(playername))
2006                 {
2007                         checkpwd = m_authmanager.getPassword(playername);
2008                 }
2009                 else
2010                 {
2011                         checkpwd = g_settings.get("default_password");
2012                 }
2013                 
2014                 if(password != checkpwd && checkpwd != "")
2015                 {
2016                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
2017                                         <<": supplied invalid password for "
2018                                         <<playername<<std::endl;
2019                         SendAccessDenied(m_con, peer_id, L"Invalid password");
2020                         return;
2021                 }
2022                 
2023                 // Add player to auth manager
2024                 if(m_authmanager.exists(playername) == false)
2025                 {
2026                         derr_server<<DTIME<<"Server: adding player "<<playername
2027                                         <<" to auth manager"<<std::endl;
2028                         m_authmanager.add(playername);
2029                         m_authmanager.setPassword(playername, checkpwd);
2030                         m_authmanager.setPrivs(playername,
2031                                         stringToPrivs(g_settings.get("default_privs")));
2032                         m_authmanager.save();
2033                 }
2034
2035                 // Get player
2036                 Player *player = emergePlayer(playername, password, peer_id);
2037
2038
2039                 /*{
2040                         // DEBUG: Test serialization
2041                         std::ostringstream test_os;
2042                         player->serialize(test_os);
2043                         dstream<<"Player serialization test: \""<<test_os.str()
2044                                         <<"\""<<std::endl;
2045                         std::istringstream test_is(test_os.str());
2046                         player->deSerialize(test_is);
2047                 }*/
2048
2049                 // If failed, cancel
2050                 if(player == NULL)
2051                 {
2052                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
2053                                         <<": failed to emerge player"<<std::endl;
2054                         return;
2055                 }
2056
2057                 /*
2058                 // If a client is already connected to the player, cancel
2059                 if(player->peer_id != 0)
2060                 {
2061                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
2062                                         <<" tried to connect to "
2063                                         "an already connected player (peer_id="
2064                                         <<player->peer_id<<")"<<std::endl;
2065                         return;
2066                 }
2067                 // Set client of player
2068                 player->peer_id = peer_id;
2069                 */
2070
2071                 // Check if player doesn't exist
2072                 if(player == NULL)
2073                         throw con::InvalidIncomingDataException
2074                                 ("Server::ProcessData(): INIT: Player doesn't exist");
2075
2076                 /*// update name if it was supplied
2077                 if(datasize >= 20+3)
2078                 {
2079                         data[20+3-1] = 0;
2080                         player->updateName((const char*)&data[3]);
2081                 }*/
2082                 
2083                 /*
2084                         Answer with a TOCLIENT_INIT
2085                 */
2086                 {
2087                         SharedBuffer<u8> reply(2+1+6+8);
2088                         writeU16(&reply[0], TOCLIENT_INIT);
2089                         writeU8(&reply[2], deployed);
2090                         writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2091                         writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
2092                         
2093                         // Send as reliable
2094                         m_con.Send(peer_id, 0, reply, true);
2095                 }
2096
2097                 /*
2098                         Send complete position information
2099                 */
2100                 SendMovePlayer(player);
2101
2102                 return;
2103         }
2104
2105         if(command == TOSERVER_INIT2)
2106         {
2107                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
2108                                 <<peer->id<<std::endl;
2109
2110
2111                 getClient(peer->id)->serialization_version
2112                                 = getClient(peer->id)->pending_serialization_version;
2113
2114                 /*
2115                         Send some initialization data
2116                 */
2117                 
2118                 // Send player info to all players
2119                 SendPlayerInfos();
2120
2121                 // Send inventory to player
2122                 UpdateCrafting(peer->id);
2123                 SendInventory(peer->id);
2124
2125                 // Send HP
2126                 {
2127                         Player *player = m_env.getPlayer(peer_id);
2128                         SendPlayerHP(player);
2129                 }
2130                 
2131                 // Send time of day
2132                 {
2133                         SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2134                                         m_env.getTimeOfDay());
2135                         m_con.Send(peer->id, 0, data, true);
2136                 }
2137                 
2138                 // Send information about server to player in chat
2139                 SendChatMessage(peer_id, getStatusString());
2140                 
2141                 // Send information about joining in chat
2142                 {
2143                         std::wstring name = L"unknown";
2144                         Player *player = m_env.getPlayer(peer_id);
2145                         if(player != NULL)
2146                                 name = narrow_to_wide(player->getName());
2147                         
2148                         std::wstring message;
2149                         message += L"*** ";
2150                         message += name;
2151                         message += L" joined game";
2152                         BroadcastChatMessage(message);
2153                 }
2154
2155                 return;
2156         }
2157
2158         if(peer_ser_ver == SER_FMT_VER_INVALID)
2159         {
2160                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
2161                                 " serialization format invalid or not initialized."
2162                                 " Skipping incoming command="<<command<<std::endl;
2163                 return;
2164         }
2165         
2166         Player *player = m_env.getPlayer(peer_id);
2167
2168         if(player == NULL){
2169                 derr_server<<"Server::ProcessData(): Cancelling: "
2170                                 "No player for peer_id="<<peer_id
2171                                 <<std::endl;
2172                 return;
2173         }
2174         if(command == TOSERVER_PLAYERPOS)
2175         {
2176                 if(datasize < 2+12+12+4+4)
2177                         return;
2178         
2179                 u32 start = 0;
2180                 v3s32 ps = readV3S32(&data[start+2]);
2181                 v3s32 ss = readV3S32(&data[start+2+12]);
2182                 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2183                 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2184                 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2185                 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2186                 pitch = wrapDegrees(pitch);
2187                 yaw = wrapDegrees(yaw);
2188                 player->setPosition(position);
2189                 player->setSpeed(speed);
2190                 player->setPitch(pitch);
2191                 player->setYaw(yaw);
2192                 
2193                 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2194                                 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2195                                 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2196         }
2197         else if(command == TOSERVER_GOTBLOCKS)
2198         {
2199                 if(datasize < 2+1)
2200                         return;
2201                 
2202                 /*
2203                         [0] u16 command
2204                         [2] u8 count
2205                         [3] v3s16 pos_0
2206                         [3+6] v3s16 pos_1
2207                         ...
2208                 */
2209
2210                 u16 count = data[2];
2211                 for(u16 i=0; i<count; i++)
2212                 {
2213                         if((s16)datasize < 2+1+(i+1)*6)
2214                                 throw con::InvalidIncomingDataException
2215                                         ("GOTBLOCKS length is too short");
2216                         v3s16 p = readV3S16(&data[2+1+i*6]);
2217                         /*dstream<<"Server: GOTBLOCKS ("
2218                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2219                         RemoteClient *client = getClient(peer_id);
2220                         client->GotBlock(p);
2221                 }
2222         }
2223         else if(command == TOSERVER_DELETEDBLOCKS)
2224         {
2225                 if(datasize < 2+1)
2226                         return;
2227                 
2228                 /*
2229                         [0] u16 command
2230                         [2] u8 count
2231                         [3] v3s16 pos_0
2232                         [3+6] v3s16 pos_1
2233                         ...
2234                 */
2235
2236                 u16 count = data[2];
2237                 for(u16 i=0; i<count; i++)
2238                 {
2239                         if((s16)datasize < 2+1+(i+1)*6)
2240                                 throw con::InvalidIncomingDataException
2241                                         ("DELETEDBLOCKS length is too short");
2242                         v3s16 p = readV3S16(&data[2+1+i*6]);
2243                         /*dstream<<"Server: DELETEDBLOCKS ("
2244                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2245                         RemoteClient *client = getClient(peer_id);
2246                         client->SetBlockNotSent(p);
2247                 }
2248         }
2249         else if(command == TOSERVER_CLICK_OBJECT)
2250         {
2251                 if(datasize < 13)
2252                         return;
2253
2254                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2255                         return;
2256
2257                 /*
2258                         [0] u16 command
2259                         [2] u8 button (0=left, 1=right)
2260                         [3] v3s16 block
2261                         [9] s16 id
2262                         [11] u16 item
2263                 */
2264                 u8 button = readU8(&data[2]);
2265                 v3s16 p;
2266                 p.X = readS16(&data[3]);
2267                 p.Y = readS16(&data[5]);
2268                 p.Z = readS16(&data[7]);
2269                 s16 id = readS16(&data[9]);
2270                 //u16 item_i = readU16(&data[11]);
2271
2272                 MapBlock *block = NULL;
2273                 try
2274                 {
2275                         block = m_env.getMap().getBlockNoCreate(p);
2276                 }
2277                 catch(InvalidPositionException &e)
2278                 {
2279                         derr_server<<"CLICK_OBJECT block not found"<<std::endl;
2280                         return;
2281                 }
2282
2283                 MapBlockObject *obj = block->getObject(id);
2284
2285                 if(obj == NULL)
2286                 {
2287                         derr_server<<"CLICK_OBJECT object not found"<<std::endl;
2288                         return;
2289                 }
2290
2291                 //TODO: Check that object is reasonably close
2292                 
2293                 // Left click
2294                 if(button == 0)
2295                 {
2296                         InventoryList *ilist = player->inventory.getList("main");
2297                         if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2298                         {
2299                         
2300                                 // Skip if inventory has no free space
2301                                 if(ilist->getUsedSlots() == ilist->getSize())
2302                                 {
2303                                         dout_server<<"Player inventory has no free space"<<std::endl;
2304                                         return;
2305                                 }
2306                                 
2307                                 /*
2308                                         Create the inventory item
2309                                 */
2310                                 InventoryItem *item = NULL;
2311                                 // If it is an item-object, take the item from it
2312                                 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
2313                                 {
2314                                         item = ((ItemObject*)obj)->createInventoryItem();
2315                                 }
2316                                 // Else create an item of the object
2317                                 else
2318                                 {
2319                                         item = new MapBlockObjectItem
2320                                                         (obj->getInventoryString());
2321                                 }
2322                                 
2323                                 // Add to inventory and send inventory
2324                                 ilist->addItem(item);
2325                                 UpdateCrafting(player->peer_id);
2326                                 SendInventory(player->peer_id);
2327                         }
2328
2329                         // Remove from block
2330                         block->removeObject(id);
2331                 }
2332         }
2333         else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2334         {
2335                 if(datasize < 7)
2336                         return;
2337
2338                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2339                         return;
2340
2341                 /*
2342                         length: 7
2343                         [0] u16 command
2344                         [2] u8 button (0=left, 1=right)
2345                         [3] u16 id
2346                         [5] u16 item
2347                 */
2348                 u8 button = readU8(&data[2]);
2349                 u16 id = readS16(&data[3]);
2350                 u16 item_i = readU16(&data[11]);
2351         
2352                 ServerActiveObject *obj = m_env.getActiveObject(id);
2353
2354                 if(obj == NULL)
2355                 {
2356                         derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2357                                         <<std::endl;
2358                         return;
2359                 }
2360
2361                 //TODO: Check that object is reasonably close
2362                 
2363                 // Left click, pick object up (usually)
2364                 if(button == 0)
2365                 {
2366                         InventoryList *ilist = player->inventory.getList("main");
2367                         if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2368                         {
2369                         
2370                                 // Skip if inventory has no free space
2371                                 if(ilist->getUsedSlots() == ilist->getSize())
2372                                 {
2373                                         dout_server<<"Player inventory has no free space"<<std::endl;
2374                                         return;
2375                                 }
2376
2377                                 // Skip if object has been removed
2378                                 if(obj->m_removed)
2379                                         return;
2380                                 
2381                                 /*
2382                                         Create the inventory item
2383                                 */
2384                                 InventoryItem *item = obj->createPickedUpItem();
2385                                 
2386                                 if(item)
2387                                 {
2388                                         // Add to inventory and send inventory
2389                                         ilist->addItem(item);
2390                                         UpdateCrafting(player->peer_id);
2391                                         SendInventory(player->peer_id);
2392
2393                                         // Remove object from environment
2394                                         obj->m_removed = true;
2395                                 }
2396                                 else
2397                                 {
2398                                         /*
2399                                                 Item cannot be picked up. Punch it instead.
2400                                         */
2401
2402                                         ToolItem *titem = NULL;
2403                                         std::string toolname = "";
2404
2405                                         InventoryList *mlist = player->inventory.getList("main");
2406                                         if(mlist != NULL)
2407                                         {
2408                                                 InventoryItem *item = mlist->getItem(item_i);
2409                                                 if(item && (std::string)item->getName() == "ToolItem")
2410                                                 {
2411                                                         titem = (ToolItem*)item;
2412                                                         toolname = titem->getToolName();
2413                                                 }
2414                                         }
2415
2416                                         v3f playerpos = player->getPosition();
2417                                         v3f objpos = obj->getBasePosition();
2418                                         v3f dir = (objpos - playerpos).normalize();
2419                                         
2420                                         u16 wear = obj->punch(toolname, dir);
2421                                         
2422                                         if(titem)
2423                                         {
2424                                                 bool weared_out = titem->addWear(wear);
2425                                                 if(weared_out)
2426                                                         mlist->deleteItem(item_i);
2427                                                 SendInventory(player->peer_id);
2428                                         }
2429                                 }
2430                         }
2431                 }
2432         }
2433         else if(command == TOSERVER_GROUND_ACTION)
2434         {
2435                 if(datasize < 17)
2436                         return;
2437                 /*
2438                         length: 17
2439                         [0] u16 command
2440                         [2] u8 action
2441                         [3] v3s16 nodepos_undersurface
2442                         [9] v3s16 nodepos_abovesurface
2443                         [15] u16 item
2444                         actions:
2445                         0: start digging
2446                         1: place block
2447                         2: stop digging (all parameters ignored)
2448                         3: digging completed
2449                 */
2450                 u8 action = readU8(&data[2]);
2451                 v3s16 p_under;
2452                 p_under.X = readS16(&data[3]);
2453                 p_under.Y = readS16(&data[5]);
2454                 p_under.Z = readS16(&data[7]);
2455                 v3s16 p_over;
2456                 p_over.X = readS16(&data[9]);
2457                 p_over.Y = readS16(&data[11]);
2458                 p_over.Z = readS16(&data[13]);
2459                 u16 item_i = readU16(&data[15]);
2460
2461                 //TODO: Check that target is reasonably close
2462                 
2463                 /*
2464                         0: start digging
2465                 */
2466                 if(action == 0)
2467                 {
2468                         /*
2469                                 NOTE: This can be used in the future to check if
2470                                 somebody is cheating, by checking the timing.
2471                         */
2472                 } // action == 0
2473
2474                 /*
2475                         2: stop digging
2476                 */
2477                 else if(action == 2)
2478                 {
2479 #if 0
2480                         RemoteClient *client = getClient(peer->id);
2481                         JMutexAutoLock digmutex(client->m_dig_mutex);
2482                         client->m_dig_tool_item = -1;
2483 #endif
2484                 }
2485
2486                 /*
2487                         3: Digging completed
2488                 */
2489                 else if(action == 3)
2490                 {
2491                         // Mandatory parameter; actually used for nothing
2492                         core::map<v3s16, MapBlock*> modified_blocks;
2493
2494                         u8 material = CONTENT_IGNORE;
2495                         u8 mineral = MINERAL_NONE;
2496
2497                         bool cannot_remove_node = false;
2498
2499                         try
2500                         {
2501                                 MapNode n = m_env.getMap().getNode(p_under);
2502                                 // Get mineral
2503                                 mineral = n.getMineral();
2504                                 // Get material at position
2505                                 material = n.d;
2506                                 // If not yet cancelled
2507                                 if(cannot_remove_node == false)
2508                                 {
2509                                         // If it's not diggable, do nothing
2510                                         if(content_diggable(material) == false)
2511                                         {
2512                                                 derr_server<<"Server: Not finishing digging: "
2513                                                                 <<"Node not diggable"
2514                                                                 <<std::endl;
2515                                                 cannot_remove_node = true;
2516                                         }
2517                                 }
2518                                 // If not yet cancelled
2519                                 if(cannot_remove_node == false)
2520                                 {
2521                                         // Get node metadata
2522                                         NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2523                                         if(meta && meta->nodeRemovalDisabled() == true)
2524                                         {
2525                                                 derr_server<<"Server: Not finishing digging: "
2526                                                                 <<"Node metadata disables removal"
2527                                                                 <<std::endl;
2528                                                 cannot_remove_node = true;
2529                                         }
2530                                 }
2531                         }
2532                         catch(InvalidPositionException &e)
2533                         {
2534                                 derr_server<<"Server: Not finishing digging: Node not found."
2535                                                 <<" Adding block to emerge queue."
2536                                                 <<std::endl;
2537                                 m_emerge_queue.addBlock(peer_id,
2538                                                 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2539                                 cannot_remove_node = true;
2540                         }
2541
2542                         // Make sure the player is allowed to do it
2543                         if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2544                         {
2545                                 dstream<<"Player "<<player->getName()<<" cannot remove node"
2546                                                 <<" because privileges are "<<getPlayerPrivs(player)
2547                                                 <<std::endl;
2548                                 cannot_remove_node = true;
2549                         }
2550
2551                         /*
2552                                 If node can't be removed, set block to be re-sent to
2553                                 client and quit.
2554                         */
2555                         if(cannot_remove_node)
2556                         {
2557                                 derr_server<<"Server: Not finishing digging."<<std::endl;
2558
2559                                 // Client probably has wrong data.
2560                                 // Set block not sent, so that client will get
2561                                 // a valid one.
2562                                 dstream<<"Client "<<peer_id<<" tried to dig "
2563                                                 <<"node; but node cannot be removed."
2564                                                 <<" setting MapBlock not sent."<<std::endl;
2565                                 RemoteClient *client = getClient(peer_id);
2566                                 v3s16 blockpos = getNodeBlockPos(p_under);
2567                                 client->SetBlockNotSent(blockpos);
2568                                         
2569                                 return;
2570                         }
2571                         
2572                         /*
2573                                 Send the removal to all close-by players.
2574                                 - If other player is close, send REMOVENODE
2575                                 - Otherwise set blocks not sent
2576                         */
2577                         core::list<u16> far_players;
2578                         sendRemoveNode(p_under, peer_id, &far_players, 30);
2579                         
2580                         /*
2581                                 Update and send inventory
2582                         */
2583
2584                         if(g_settings.getBool("creative_mode") == false)
2585                         {
2586                                 /*
2587                                         Wear out tool
2588                                 */
2589                                 InventoryList *mlist = player->inventory.getList("main");
2590                                 if(mlist != NULL)
2591                                 {
2592                                         InventoryItem *item = mlist->getItem(item_i);
2593                                         if(item && (std::string)item->getName() == "ToolItem")
2594                                         {
2595                                                 ToolItem *titem = (ToolItem*)item;
2596                                                 std::string toolname = titem->getToolName();
2597
2598                                                 // Get digging properties for material and tool
2599                                                 DiggingProperties prop =
2600                                                                 getDiggingProperties(material, toolname);
2601
2602                                                 if(prop.diggable == false)
2603                                                 {
2604                                                         derr_server<<"Server: WARNING: Player digged"
2605                                                                         <<" with impossible material + tool"
2606                                                                         <<" combination"<<std::endl;
2607                                                 }
2608                                                 
2609                                                 bool weared_out = titem->addWear(prop.wear);
2610
2611                                                 if(weared_out)
2612                                                 {
2613                                                         mlist->deleteItem(item_i);
2614                                                 }
2615                                         }
2616                                 }
2617
2618                                 /*
2619                                         Add dug item to inventory
2620                                 */
2621
2622                                 InventoryItem *item = NULL;
2623
2624                                 if(mineral != MINERAL_NONE)
2625                                         item = getDiggedMineralItem(mineral);
2626                                 
2627                                 // If not mineral
2628                                 if(item == NULL)
2629                                 {
2630                                         std::string &dug_s = content_features(material).dug_item;
2631                                         if(dug_s != "")
2632                                         {
2633                                                 std::istringstream is(dug_s, std::ios::binary);
2634                                                 item = InventoryItem::deSerialize(is);
2635                                         }
2636                                 }
2637                                 
2638                                 if(item != NULL)
2639                                 {
2640                                         // Add a item to inventory
2641                                         player->inventory.addItem("main", item);
2642
2643                                         // Send inventory
2644                                         UpdateCrafting(player->peer_id);
2645                                         SendInventory(player->peer_id);
2646                                 }
2647                         }
2648
2649                         /*
2650                                 Remove the node
2651                                 (this takes some time so it is done after the quick stuff)
2652                         */
2653                         {
2654                                 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2655
2656                                 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2657                         }
2658                         /*
2659                                 Set blocks not sent to far players
2660                         */
2661                         for(core::list<u16>::Iterator
2662                                         i = far_players.begin();
2663                                         i != far_players.end(); i++)
2664                         {
2665                                 u16 peer_id = *i;
2666                                 RemoteClient *client = getClient(peer_id);
2667                                 if(client==NULL)
2668                                         continue;
2669                                 client->SetBlocksNotSent(modified_blocks);
2670                         }
2671                 }
2672                 
2673                 /*
2674                         1: place block
2675                 */
2676                 else if(action == 1)
2677                 {
2678
2679                         InventoryList *ilist = player->inventory.getList("main");
2680                         if(ilist == NULL)
2681                                 return;
2682
2683                         // Get item
2684                         InventoryItem *item = ilist->getItem(item_i);
2685                         
2686                         // If there is no item, it is not possible to add it anywhere
2687                         if(item == NULL)
2688                                 return;
2689                         
2690                         /*
2691                                 Handle material items
2692                         */
2693                         if(std::string("MaterialItem") == item->getName())
2694                         {
2695                                 try{
2696                                         // Don't add a node if this is not a free space
2697                                         MapNode n2 = m_env.getMap().getNode(p_over);
2698                                         bool no_enough_privs =
2699                                                         ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2700                                         if(no_enough_privs)
2701                                                 dstream<<"Player "<<player->getName()<<" cannot add node"
2702                                                         <<" because privileges are "<<getPlayerPrivs(player)
2703                                                         <<std::endl;
2704
2705                                         if(content_buildable_to(n2.d) == false
2706                                                 || no_enough_privs)
2707                                         {
2708                                                 // Client probably has wrong data.
2709                                                 // Set block not sent, so that client will get
2710                                                 // a valid one.
2711                                                 dstream<<"Client "<<peer_id<<" tried to place"
2712                                                                 <<" node in invalid position; setting"
2713                                                                 <<" MapBlock not sent."<<std::endl;
2714                                                 RemoteClient *client = getClient(peer_id);
2715                                                 v3s16 blockpos = getNodeBlockPos(p_over);
2716                                                 client->SetBlockNotSent(blockpos);
2717                                                 return;
2718                                         }
2719                                 }
2720                                 catch(InvalidPositionException &e)
2721                                 {
2722                                         derr_server<<"Server: Ignoring ADDNODE: Node not found"
2723                                                         <<" Adding block to emerge queue."
2724                                                         <<std::endl;
2725                                         m_emerge_queue.addBlock(peer_id,
2726                                                         getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2727                                         return;
2728                                 }
2729
2730                                 // Reset build time counter
2731                                 getClient(peer->id)->m_time_from_building = 0.0;
2732                                 
2733                                 // Create node data
2734                                 MaterialItem *mitem = (MaterialItem*)item;
2735                                 MapNode n;
2736                                 n.d = mitem->getMaterial();
2737                                 if(content_features(n.d).wall_mounted)
2738                                         n.dir = packDir(p_under - p_over);
2739                                 
2740                                 /*
2741                                         Send to all close-by players
2742                                 */
2743                                 core::list<u16> far_players;
2744                                 sendAddNode(p_over, n, 0, &far_players, 30);
2745                                 
2746                                 /*
2747                                         Handle inventory
2748                                 */
2749                                 InventoryList *ilist = player->inventory.getList("main");
2750                                 if(g_settings.getBool("creative_mode") == false && ilist)
2751                                 {
2752                                         // Remove from inventory and send inventory
2753                                         if(mitem->getCount() == 1)
2754                                                 ilist->deleteItem(item_i);
2755                                         else
2756                                                 mitem->remove(1);
2757                                         // Send inventory
2758                                         UpdateCrafting(peer_id);
2759                                         SendInventory(peer_id);
2760                                 }
2761                                 
2762                                 /*
2763                                         Add node.
2764
2765                                         This takes some time so it is done after the quick stuff
2766                                 */
2767                                 core::map<v3s16, MapBlock*> modified_blocks;
2768                                 {
2769                                         MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2770
2771                                         m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2772                                 }
2773                                 /*
2774                                         Set blocks not sent to far players
2775                                 */
2776                                 for(core::list<u16>::Iterator
2777                                                 i = far_players.begin();
2778                                                 i != far_players.end(); i++)
2779                                 {
2780                                         u16 peer_id = *i;
2781                                         RemoteClient *client = getClient(peer_id);
2782                                         if(client==NULL)
2783                                                 continue;
2784                                         client->SetBlocksNotSent(modified_blocks);
2785                                 }
2786
2787                                 /*
2788                                         Calculate special events
2789                                 */
2790                                 
2791                                 /*if(n.d == CONTENT_MESE)
2792                                 {
2793                                         u32 count = 0;
2794                                         for(s16 z=-1; z<=1; z++)
2795                                         for(s16 y=-1; y<=1; y++)
2796                                         for(s16 x=-1; x<=1; x++)
2797                                         {
2798                                                 
2799                                         }
2800                                 }*/
2801                         }
2802                         /*
2803                                 Place other item (not a block)
2804                         */
2805                         else
2806                         {
2807                                 v3s16 blockpos = getNodeBlockPos(p_over);
2808                                 
2809                                 /*
2810                                         Check that the block is loaded so that the item
2811                                         can properly be added to the static list too
2812                                 */
2813                                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2814                                 if(block==NULL)
2815                                 {
2816                                         derr_server<<"Error while placing object: "
2817                                                         "block not found"<<std::endl;
2818                                         return;
2819                                 }
2820
2821                                 dout_server<<"Placing a miscellaneous item on map"
2822                                                 <<std::endl;
2823                                 
2824                                 // Calculate a position for it
2825                                 v3f pos = intToFloat(p_over, BS);
2826                                 //pos.Y -= BS*0.45;
2827                                 pos.Y -= BS*0.25; // let it drop a bit
2828                                 // Randomize a bit
2829                                 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2830                                 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2831
2832                                 /*
2833                                         Create the object
2834                                 */
2835                                 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2836
2837                                 if(obj == NULL)
2838                                 {
2839                                         derr_server<<"WARNING: item resulted in NULL object, "
2840                                                         <<"not placing onto map"
2841                                                         <<std::endl;
2842                                 }
2843                                 else
2844                                 {
2845                                         // Add the object to the environment
2846                                         m_env.addActiveObject(obj);
2847                                         
2848                                         dout_server<<"Placed object"<<std::endl;
2849
2850                                         if(g_settings.getBool("creative_mode") == false)
2851                                         {
2852                                                 // Delete the right amount of items from the slot
2853                                                 u16 dropcount = item->getDropCount();
2854                                                 
2855                                                 // Delete item if all gone
2856                                                 if(item->getCount() <= dropcount)
2857                                                 {
2858                                                         if(item->getCount() < dropcount)
2859                                                                 dstream<<"WARNING: Server: dropped more items"
2860                                                                                 <<" than the slot contains"<<std::endl;
2861                                                         
2862                                                         InventoryList *ilist = player->inventory.getList("main");
2863                                                         if(ilist)
2864                                                                 // Remove from inventory and send inventory
2865                                                                 ilist->deleteItem(item_i);
2866                                                 }
2867                                                 // Else decrement it
2868                                                 else
2869                                                         item->remove(dropcount);
2870                                                 
2871                                                 // Send inventory
2872                                                 UpdateCrafting(peer_id);
2873                                                 SendInventory(peer_id);
2874                                         }
2875                                 }
2876                         }
2877
2878                 } // action == 1
2879
2880                 /*
2881                         Catch invalid actions
2882                 */
2883                 else
2884                 {
2885                         derr_server<<"WARNING: Server: Invalid action "
2886                                         <<action<<std::endl;
2887                 }
2888         }
2889 #if 0
2890         else if(command == TOSERVER_RELEASE)
2891         {
2892                 if(datasize < 3)
2893                         return;
2894                 /*
2895                         length: 3
2896                         [0] u16 command
2897                         [2] u8 button
2898                 */
2899                 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
2900         }
2901 #endif
2902         else if(command == TOSERVER_SIGNTEXT)
2903         {
2904                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2905                         return;
2906                 /*
2907                         u16 command
2908                         v3s16 blockpos
2909                         s16 id
2910                         u16 textlen
2911                         textdata
2912                 */
2913                 std::string datastring((char*)&data[2], datasize-2);
2914                 std::istringstream is(datastring, std::ios_base::binary);
2915                 u8 buf[6];
2916                 // Read stuff
2917                 is.read((char*)buf, 6);
2918                 v3s16 blockpos = readV3S16(buf);
2919                 is.read((char*)buf, 2);
2920                 s16 id = readS16(buf);
2921                 is.read((char*)buf, 2);
2922                 u16 textlen = readU16(buf);
2923                 std::string text;
2924                 for(u16 i=0; i<textlen; i++)
2925                 {
2926                         is.read((char*)buf, 1);
2927                         text += (char)buf[0];
2928                 }
2929
2930                 MapBlock *block = NULL;
2931                 try
2932                 {
2933                         block = m_env.getMap().getBlockNoCreate(blockpos);
2934                 }
2935                 catch(InvalidPositionException &e)
2936                 {
2937                         derr_server<<"Error while setting sign text: "
2938                                         "block not found"<<std::endl;
2939                         return;
2940                 }
2941
2942                 MapBlockObject *obj = block->getObject(id);
2943                 if(obj == NULL)
2944                 {
2945                         derr_server<<"Error while setting sign text: "
2946                                         "object not found"<<std::endl;
2947                         return;
2948                 }
2949                 
2950                 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
2951                 {
2952                         derr_server<<"Error while setting sign text: "
2953                                         "object is not a sign"<<std::endl;
2954                         return;
2955                 }
2956
2957                 ((SignObject*)obj)->setText(text);
2958
2959                 obj->getBlock()->setChangedFlag();
2960         }
2961         else if(command == TOSERVER_SIGNNODETEXT)
2962         {
2963                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2964                         return;
2965                 /*
2966                         u16 command
2967                         v3s16 p
2968                         u16 textlen
2969                         textdata
2970                 */
2971                 std::string datastring((char*)&data[2], datasize-2);
2972                 std::istringstream is(datastring, std::ios_base::binary);
2973                 u8 buf[6];
2974                 // Read stuff
2975                 is.read((char*)buf, 6);
2976                 v3s16 p = readV3S16(buf);
2977                 is.read((char*)buf, 2);
2978                 u16 textlen = readU16(buf);
2979                 std::string text;
2980                 for(u16 i=0; i<textlen; i++)
2981                 {
2982                         is.read((char*)buf, 1);
2983                         text += (char)buf[0];
2984                 }
2985
2986                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
2987                 if(!meta)
2988                         return;
2989                 if(meta->typeId() != CONTENT_SIGN_WALL)
2990                         return;
2991                 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
2992                 signmeta->setText(text);
2993                 
2994                 v3s16 blockpos = getNodeBlockPos(p);
2995                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2996                 if(block)
2997                 {
2998                         block->setChangedFlag();
2999                 }
3000
3001                 for(core::map<u16, RemoteClient*>::Iterator
3002                         i = m_clients.getIterator();
3003                         i.atEnd()==false; i++)
3004                 {
3005                         RemoteClient *client = i.getNode()->getValue();
3006                         client->SetBlockNotSent(blockpos);
3007                 }
3008         }
3009         else if(command == TOSERVER_INVENTORY_ACTION)
3010         {
3011                 /*// Ignore inventory changes if in creative mode
3012                 if(g_settings.getBool("creative_mode") == true)
3013                 {
3014                         dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3015                                         <<std::endl;
3016                         return;
3017                 }*/
3018                 // Strip command and create a stream
3019                 std::string datastring((char*)&data[2], datasize-2);
3020                 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3021                 std::istringstream is(datastring, std::ios_base::binary);
3022                 // Create an action
3023                 InventoryAction *a = InventoryAction::deSerialize(is);
3024                 if(a != NULL)
3025                 {
3026                         // Create context
3027                         InventoryContext c;
3028                         c.current_player = player;
3029
3030                         /*
3031                                 Handle craftresult specially if not in creative mode
3032                         */
3033                         bool disable_action = false;
3034                         if(a->getType() == IACTION_MOVE
3035                                         && g_settings.getBool("creative_mode") == false)
3036                         {
3037                                 IMoveAction *ma = (IMoveAction*)a;
3038                                 if(ma->to_inv == "current_player" &&
3039                                                 ma->from_inv == "current_player")
3040                                 {
3041                                         InventoryList *rlist = player->inventory.getList("craftresult");
3042                                         assert(rlist);
3043                                         InventoryList *clist = player->inventory.getList("craft");
3044                                         assert(clist);
3045                                         InventoryList *mlist = player->inventory.getList("main");
3046                                         assert(mlist);
3047                                         /*
3048                                                 Craftresult is no longer preview if something
3049                                                 is moved into it
3050                                         */
3051                                         if(ma->to_list == "craftresult"
3052                                                         && ma->from_list != "craftresult")
3053                                         {
3054                                                 // If it currently is a preview, remove
3055                                                 // its contents
3056                                                 if(player->craftresult_is_preview)
3057                                                 {
3058                                                         rlist->deleteItem(0);
3059                                                 }
3060                                                 player->craftresult_is_preview = false;
3061                                         }
3062                                         /*
3063                                                 Crafting takes place if this condition is true.
3064                                         */
3065                                         if(player->craftresult_is_preview &&
3066                                                         ma->from_list == "craftresult")
3067                                         {
3068                                                 player->craftresult_is_preview = false;
3069                                                 clist->decrementMaterials(1);
3070                                         }
3071                                         /*
3072                                                 If the craftresult is placed on itself, move it to
3073                                                 main inventory instead of doing the action
3074                                         */
3075                                         if(ma->to_list == "craftresult"
3076                                                         && ma->from_list == "craftresult")
3077                                         {
3078                                                 disable_action = true;
3079                                                 
3080                                                 InventoryItem *item1 = rlist->changeItem(0, NULL);
3081                                                 mlist->addItem(item1);
3082                                         }
3083                                 }
3084                         }
3085                         
3086                         if(disable_action == false)
3087                         {
3088                                 // Feed action to player inventory
3089                                 a->apply(&c, this);
3090                                 // Eat the action
3091                                 delete a;
3092                         }
3093                         else
3094                         {
3095                                 // Send inventory
3096                                 UpdateCrafting(player->peer_id);
3097                                 SendInventory(player->peer_id);
3098                         }
3099                 }
3100                 else
3101                 {
3102                         dstream<<"TOSERVER_INVENTORY_ACTION: "
3103                                         <<"InventoryAction::deSerialize() returned NULL"
3104                                         <<std::endl;
3105                 }
3106         }
3107         else if(command == TOSERVER_CHAT_MESSAGE)
3108         {
3109                 /*
3110                         u16 command
3111                         u16 length
3112                         wstring message
3113                 */
3114                 u8 buf[6];
3115                 std::string datastring((char*)&data[2], datasize-2);
3116                 std::istringstream is(datastring, std::ios_base::binary);
3117                 
3118                 // Read stuff
3119                 is.read((char*)buf, 2);
3120                 u16 len = readU16(buf);
3121                 
3122                 std::wstring message;
3123                 for(u16 i=0; i<len; i++)
3124                 {
3125                         is.read((char*)buf, 2);
3126                         message += (wchar_t)readU16(buf);
3127                 }
3128
3129                 // Get player name of this client
3130                 std::wstring name = narrow_to_wide(player->getName());
3131                 
3132                 // Line to send to players
3133                 std::wstring line;
3134                 // Whether to send to the player that sent the line
3135                 bool send_to_sender = false;
3136                 // Whether to send to other players
3137                 bool send_to_others = false;
3138                 
3139                 // Local player gets all privileges regardless of
3140                 // what's set on their account.
3141                 u64 privs = getPlayerPrivs(player);
3142
3143                 // Parse commands
3144                 std::wstring commandprefix = L"/#";
3145                 if(message.substr(0, commandprefix.size()) == commandprefix)
3146                 {
3147                         line += L"Server: ";
3148
3149                         message = message.substr(commandprefix.size());
3150
3151                         ServerCommandContext *ctx = new ServerCommandContext(
3152                                 str_split(message, L' '),
3153                                 this,
3154                                 &m_env,
3155                                 player,
3156                                 privs);
3157
3158                         line += processServerCommand(ctx);
3159                         send_to_sender = ctx->flags & 1;
3160                         send_to_others = ctx->flags & 2;
3161                         delete ctx;
3162
3163                 }
3164                 else
3165                 {
3166                         if(privs & PRIV_SHOUT)
3167                         {
3168                                 line += L"<";
3169                                 line += name;
3170                                 line += L"> ";
3171                                 line += message;
3172                                 send_to_others = true;
3173                         }
3174                         else
3175                         {
3176                                 line += L"Server: You are not allowed to shout";
3177                                 send_to_sender = true;
3178                         }
3179                 }
3180                 
3181                 if(line != L"")
3182                 {
3183                         dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3184
3185                         /*
3186                                 Send the message to clients
3187                         */
3188                         for(core::map<u16, RemoteClient*>::Iterator
3189                                 i = m_clients.getIterator();
3190                                 i.atEnd() == false; i++)
3191                         {
3192                                 // Get client and check that it is valid
3193                                 RemoteClient *client = i.getNode()->getValue();
3194                                 assert(client->peer_id == i.getNode()->getKey());
3195                                 if(client->serialization_version == SER_FMT_VER_INVALID)
3196                                         continue;
3197
3198                                 // Filter recipient
3199                                 bool sender_selected = (peer_id == client->peer_id);
3200                                 if(sender_selected == true && send_to_sender == false)
3201                                         continue;
3202                                 if(sender_selected == false && send_to_others == false)
3203                                         continue;
3204
3205                                 SendChatMessage(client->peer_id, line);
3206                         }
3207                 }
3208         }
3209         else if(command == TOSERVER_DAMAGE)
3210         {
3211                 if(g_settings.getBool("enable_damage"))
3212                 {
3213                         std::string datastring((char*)&data[2], datasize-2);
3214                         std::istringstream is(datastring, std::ios_base::binary);
3215                         u8 damage = readU8(is);
3216                         if(player->hp > damage)
3217                         {
3218                                 player->hp -= damage;
3219                         }
3220                         else
3221                         {
3222                                 player->hp = 0;
3223
3224                                 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3225                                                 <<std::endl;
3226                                 
3227                                 v3f pos = findSpawnPos(m_env.getServerMap());
3228                                 player->setPosition(pos);
3229                                 player->hp = 20;
3230                                 SendMovePlayer(player);
3231                                 SendPlayerHP(player);
3232                                 
3233                                 //TODO: Throw items around
3234                         }
3235                 }
3236
3237                 SendPlayerHP(player);
3238         }
3239         else if(command == TOSERVER_PASSWORD)
3240         {
3241                 /*
3242                         [0] u16 TOSERVER_PASSWORD
3243                         [2] u8[28] old password
3244                         [30] u8[28] new password
3245                 */
3246
3247                 if(datasize != 2+PASSWORD_SIZE*2)
3248                         return;
3249                 /*char password[PASSWORD_SIZE];
3250                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3251                         password[i] = data[2+i];
3252                 password[PASSWORD_SIZE-1] = 0;*/
3253                 std::string oldpwd;
3254                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3255                 {
3256                         char c = data[2+i];
3257                         if(c == 0)
3258                                 break;
3259                         oldpwd += c;
3260                 }
3261                 std::string newpwd;
3262                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3263                 {
3264                         char c = data[2+PASSWORD_SIZE+i];
3265                         if(c == 0)
3266                                 break;
3267                         newpwd += c;
3268                 }
3269
3270                 std::string playername = player->getName();
3271
3272                 if(m_authmanager.exists(playername) == false)
3273                 {
3274                         dstream<<"Server: playername not found in authmanager"<<std::endl;
3275                         // Wrong old password supplied!!
3276                         SendChatMessage(peer_id, L"playername not found in authmanager");
3277                         return;
3278                 }
3279
3280                 std::string checkpwd = m_authmanager.getPassword(playername);
3281                 
3282                 if(oldpwd != checkpwd)
3283                 {
3284                         dstream<<"Server: invalid old password"<<std::endl;
3285                         // Wrong old password supplied!!
3286                         SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3287                         return;
3288                 }
3289
3290                 m_authmanager.setPassword(playername, newpwd);
3291                 
3292                 dstream<<"Server: password change successful for "<<playername
3293                                 <<std::endl;
3294                 SendChatMessage(peer_id, L"Password change successful");
3295         }
3296         else
3297         {
3298                 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3299                                 "unknown command "<<command<<std::endl;
3300         }
3301         
3302         } //try
3303         catch(SendFailedException &e)
3304         {
3305                 derr_server<<"Server::ProcessData(): SendFailedException: "
3306                                 <<"what="<<e.what()
3307                                 <<std::endl;
3308         }
3309 }
3310
3311 void Server::onMapEditEvent(MapEditEvent *event)
3312 {
3313         dstream<<"Server::onMapEditEvent()"<<std::endl;
3314         if(m_ignore_map_edit_events)
3315                 return;
3316         MapEditEvent *e = event->clone();
3317         m_unsent_map_edit_queue.push_back(e);
3318 }
3319
3320 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3321 {
3322         if(id == "current_player")
3323         {
3324                 assert(c->current_player);
3325                 return &(c->current_player->inventory);
3326         }
3327         
3328         Strfnd fn(id);
3329         std::string id0 = fn.next(":");
3330
3331         if(id0 == "nodemeta")
3332         {
3333                 v3s16 p;
3334                 p.X = stoi(fn.next(","));
3335                 p.Y = stoi(fn.next(","));
3336                 p.Z = stoi(fn.next(","));
3337                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3338                 if(meta)
3339                         return meta->getInventory();
3340                 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3341                                 <<"no metadata found"<<std::endl;
3342                 return NULL;
3343         }
3344
3345         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3346         return NULL;
3347 }
3348 void Server::inventoryModified(InventoryContext *c, std::string id)
3349 {
3350         if(id == "current_player")
3351         {
3352                 assert(c->current_player);
3353                 // Send inventory
3354                 UpdateCrafting(c->current_player->peer_id);
3355                 SendInventory(c->current_player->peer_id);
3356                 return;
3357         }
3358         
3359         Strfnd fn(id);
3360         std::string id0 = fn.next(":");
3361
3362         if(id0 == "nodemeta")
3363         {
3364                 v3s16 p;
3365                 p.X = stoi(fn.next(","));
3366                 p.Y = stoi(fn.next(","));
3367                 p.Z = stoi(fn.next(","));
3368                 v3s16 blockpos = getNodeBlockPos(p);
3369
3370                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3371                 if(meta)
3372                         meta->inventoryModified();
3373
3374                 for(core::map<u16, RemoteClient*>::Iterator
3375                         i = m_clients.getIterator();
3376                         i.atEnd()==false; i++)
3377                 {
3378                         RemoteClient *client = i.getNode()->getValue();
3379                         client->SetBlockNotSent(blockpos);
3380                 }
3381
3382                 return;
3383         }
3384
3385         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3386 }
3387
3388 core::list<PlayerInfo> Server::getPlayerInfo()
3389 {
3390         DSTACK(__FUNCTION_NAME);
3391         JMutexAutoLock envlock(m_env_mutex);
3392         JMutexAutoLock conlock(m_con_mutex);
3393         
3394         core::list<PlayerInfo> list;
3395
3396         core::list<Player*> players = m_env.getPlayers();
3397         
3398         core::list<Player*>::Iterator i;
3399         for(i = players.begin();
3400                         i != players.end(); i++)
3401         {
3402                 PlayerInfo info;
3403
3404                 Player *player = *i;
3405
3406                 try{
3407                         con::Peer *peer = m_con.GetPeer(player->peer_id);
3408                         // Copy info from peer to info struct
3409                         info.id = peer->id;
3410                         info.address = peer->address;
3411                         info.avg_rtt = peer->avg_rtt;
3412                 }
3413                 catch(con::PeerNotFoundException &e)
3414                 {
3415                         // Set dummy peer info
3416                         info.id = 0;
3417                         info.address = Address(0,0,0,0,0);
3418                         info.avg_rtt = 0.0;
3419                 }
3420
3421                 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3422                 info.position = player->getPosition();
3423
3424                 list.push_back(info);
3425         }
3426
3427         return list;
3428 }
3429
3430
3431 void Server::peerAdded(con::Peer *peer)
3432 {
3433         DSTACK(__FUNCTION_NAME);
3434         dout_server<<"Server::peerAdded(): peer->id="
3435                         <<peer->id<<std::endl;
3436         
3437         PeerChange c;
3438         c.type = PEER_ADDED;
3439         c.peer_id = peer->id;
3440         c.timeout = false;
3441         m_peer_change_queue.push_back(c);
3442 }
3443
3444 void Server::deletingPeer(con::Peer *peer, bool timeout)
3445 {
3446         DSTACK(__FUNCTION_NAME);
3447         dout_server<<"Server::deletingPeer(): peer->id="
3448                         <<peer->id<<", timeout="<<timeout<<std::endl;
3449         
3450         PeerChange c;
3451         c.type = PEER_REMOVED;
3452         c.peer_id = peer->id;
3453         c.timeout = timeout;
3454         m_peer_change_queue.push_back(c);
3455 }
3456
3457 /*
3458         Static send methods
3459 */
3460
3461 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3462 {
3463         DSTACK(__FUNCTION_NAME);
3464         std::ostringstream os(std::ios_base::binary);
3465
3466         writeU16(os, TOCLIENT_HP);
3467         writeU8(os, hp);
3468
3469         // Make data buffer
3470         std::string s = os.str();
3471         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3472         // Send as reliable
3473         con.Send(peer_id, 0, data, true);
3474 }
3475
3476 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3477                 const std::wstring &reason)
3478 {
3479         DSTACK(__FUNCTION_NAME);
3480         std::ostringstream os(std::ios_base::binary);
3481
3482         writeU16(os, TOCLIENT_ACCESS_DENIED);
3483         os<<serializeWideString(reason);
3484
3485         // Make data buffer
3486         std::string s = os.str();
3487         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3488         // Send as reliable
3489         con.Send(peer_id, 0, data, true);
3490 }
3491
3492 /*
3493         Non-static send methods
3494 */
3495
3496 void Server::SendObjectData(float dtime)
3497 {
3498         DSTACK(__FUNCTION_NAME);
3499
3500         core::map<v3s16, bool> stepped_blocks;
3501         
3502         for(core::map<u16, RemoteClient*>::Iterator
3503                 i = m_clients.getIterator();
3504                 i.atEnd() == false; i++)
3505         {
3506                 u16 peer_id = i.getNode()->getKey();
3507                 RemoteClient *client = i.getNode()->getValue();
3508                 assert(client->peer_id == peer_id);
3509                 
3510                 if(client->serialization_version == SER_FMT_VER_INVALID)
3511                         continue;
3512                 
3513                 client->SendObjectData(this, dtime, stepped_blocks);
3514         }
3515 }
3516
3517 void Server::SendPlayerInfos()
3518 {
3519         DSTACK(__FUNCTION_NAME);
3520
3521         //JMutexAutoLock envlock(m_env_mutex);
3522         
3523         // Get connected players
3524         core::list<Player*> players = m_env.getPlayers(true);
3525         
3526         u32 player_count = players.getSize();
3527         u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3528
3529         SharedBuffer<u8> data(datasize);
3530         writeU16(&data[0], TOCLIENT_PLAYERINFO);
3531         
3532         u32 start = 2;
3533         core::list<Player*>::Iterator i;
3534         for(i = players.begin();
3535                         i != players.end(); i++)
3536         {
3537                 Player *player = *i;
3538
3539                 /*dstream<<"Server sending player info for player with "
3540                                 "peer_id="<<player->peer_id<<std::endl;*/
3541                 
3542                 writeU16(&data[start], player->peer_id);
3543                 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3544                 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3545                 start += 2+PLAYERNAME_SIZE;
3546         }
3547
3548         //JMutexAutoLock conlock(m_con_mutex);
3549
3550         // Send as reliable
3551         m_con.SendToAll(0, data, true);
3552 }
3553
3554 void Server::SendInventory(u16 peer_id)
3555 {
3556         DSTACK(__FUNCTION_NAME);
3557         
3558         Player* player = m_env.getPlayer(peer_id);
3559         assert(player);
3560
3561         /*
3562                 Serialize it
3563         */
3564
3565         std::ostringstream os;
3566         //os.imbue(std::locale("C"));
3567
3568         player->inventory.serialize(os);
3569
3570         std::string s = os.str();
3571         
3572         SharedBuffer<u8> data(s.size()+2);
3573         writeU16(&data[0], TOCLIENT_INVENTORY);
3574         memcpy(&data[2], s.c_str(), s.size());
3575         
3576         // Send as reliable
3577         m_con.Send(peer_id, 0, data, true);
3578 }
3579
3580 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3581 {
3582         DSTACK(__FUNCTION_NAME);
3583         
3584         std::ostringstream os(std::ios_base::binary);
3585         u8 buf[12];
3586         
3587         // Write command
3588         writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3589         os.write((char*)buf, 2);
3590         
3591         // Write length
3592         writeU16(buf, message.size());
3593         os.write((char*)buf, 2);
3594         
3595         // Write string
3596         for(u32 i=0; i<message.size(); i++)
3597         {
3598                 u16 w = message[i];
3599                 writeU16(buf, w);
3600                 os.write((char*)buf, 2);
3601         }
3602         
3603         // Make data buffer
3604         std::string s = os.str();
3605         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3606         // Send as reliable
3607         m_con.Send(peer_id, 0, data, true);
3608 }
3609
3610 void Server::BroadcastChatMessage(const std::wstring &message)
3611 {
3612         for(core::map<u16, RemoteClient*>::Iterator
3613                 i = m_clients.getIterator();
3614                 i.atEnd() == false; i++)
3615         {
3616                 // Get client and check that it is valid
3617                 RemoteClient *client = i.getNode()->getValue();
3618                 assert(client->peer_id == i.getNode()->getKey());
3619                 if(client->serialization_version == SER_FMT_VER_INVALID)
3620                         continue;
3621
3622                 SendChatMessage(client->peer_id, message);
3623         }
3624 }
3625
3626 void Server::SendPlayerHP(Player *player)
3627 {
3628         SendHP(m_con, player->peer_id, player->hp);
3629 }
3630
3631 void Server::SendMovePlayer(Player *player)
3632 {
3633         DSTACK(__FUNCTION_NAME);
3634         std::ostringstream os(std::ios_base::binary);
3635
3636         writeU16(os, TOCLIENT_MOVE_PLAYER);
3637         writeV3F1000(os, player->getPosition());
3638         writeF1000(os, player->getPitch());
3639         writeF1000(os, player->getYaw());
3640         
3641         {
3642                 v3f pos = player->getPosition();
3643                 f32 pitch = player->getPitch();
3644                 f32 yaw = player->getYaw();
3645                 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3646                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3647                                 <<" pitch="<<pitch
3648                                 <<" yaw="<<yaw
3649                                 <<std::endl;
3650         }
3651
3652         // Make data buffer
3653         std::string s = os.str();
3654         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3655         // Send as reliable
3656         m_con.Send(player->peer_id, 0, data, true);
3657 }
3658
3659 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3660         core::list<u16> *far_players, float far_d_nodes)
3661 {
3662         float maxd = far_d_nodes*BS;
3663         v3f p_f = intToFloat(p, BS);
3664
3665         // Create packet
3666         u32 replysize = 8;
3667         SharedBuffer<u8> reply(replysize);
3668         writeU16(&reply[0], TOCLIENT_REMOVENODE);
3669         writeS16(&reply[2], p.X);
3670         writeS16(&reply[4], p.Y);
3671         writeS16(&reply[6], p.Z);
3672
3673         for(core::map<u16, RemoteClient*>::Iterator
3674                 i = m_clients.getIterator();
3675                 i.atEnd() == false; i++)
3676         {
3677                 // Get client and check that it is valid
3678                 RemoteClient *client = i.getNode()->getValue();
3679                 assert(client->peer_id == i.getNode()->getKey());
3680                 if(client->serialization_version == SER_FMT_VER_INVALID)
3681                         continue;
3682
3683                 // Don't send if it's the same one
3684                 if(client->peer_id == ignore_id)
3685                         continue;
3686                 
3687                 if(far_players)
3688                 {
3689                         // Get player
3690                         Player *player = m_env.getPlayer(client->peer_id);
3691                         if(player)
3692                         {
3693                                 // If player is far away, only set modified blocks not sent
3694                                 v3f player_pos = player->getPosition();
3695                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3696                                 {
3697                                         far_players->push_back(client->peer_id);
3698                                         continue;
3699                                 }
3700                         }
3701                 }
3702
3703                 // Send as reliable
3704                 m_con.Send(client->peer_id, 0, reply, true);
3705         }
3706 }
3707
3708 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3709                 core::list<u16> *far_players, float far_d_nodes)
3710 {
3711         float maxd = far_d_nodes*BS;
3712         v3f p_f = intToFloat(p, BS);
3713
3714         for(core::map<u16, RemoteClient*>::Iterator
3715                 i = m_clients.getIterator();
3716                 i.atEnd() == false; i++)
3717         {
3718                 // Get client and check that it is valid
3719                 RemoteClient *client = i.getNode()->getValue();
3720                 assert(client->peer_id == i.getNode()->getKey());
3721                 if(client->serialization_version == SER_FMT_VER_INVALID)
3722                         continue;
3723
3724                 // Don't send if it's the same one
3725                 if(client->peer_id == ignore_id)
3726                         continue;
3727
3728                 if(far_players)
3729                 {
3730                         // Get player
3731                         Player *player = m_env.getPlayer(client->peer_id);
3732                         if(player)
3733                         {
3734                                 // If player is far away, only set modified blocks not sent
3735                                 v3f player_pos = player->getPosition();
3736                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3737                                 {
3738                                         far_players->push_back(client->peer_id);
3739                                         continue;
3740                                 }
3741                         }
3742                 }
3743
3744                 // Create packet
3745                 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3746                 SharedBuffer<u8> reply(replysize);
3747                 writeU16(&reply[0], TOCLIENT_ADDNODE);
3748                 writeS16(&reply[2], p.X);
3749                 writeS16(&reply[4], p.Y);
3750                 writeS16(&reply[6], p.Z);
3751                 n.serialize(&reply[8], client->serialization_version);
3752
3753                 // Send as reliable
3754                 m_con.Send(client->peer_id, 0, reply, true);
3755         }
3756 }
3757
3758 void Server::setBlockNotSent(v3s16 p)
3759 {
3760         for(core::map<u16, RemoteClient*>::Iterator
3761                 i = m_clients.getIterator();
3762                 i.atEnd()==false; i++)
3763         {
3764                 RemoteClient *client = i.getNode()->getValue();
3765                 client->SetBlockNotSent(p);
3766         }
3767 }
3768
3769 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3770 {
3771         DSTACK(__FUNCTION_NAME);
3772
3773         v3s16 p = block->getPos();
3774         
3775 #if 0
3776         // Analyze it a bit
3777         bool completely_air = true;
3778         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3779         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3780         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3781         {
3782                 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3783                 {
3784                         completely_air = false;
3785                         x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3786                 }
3787         }
3788
3789         // Print result
3790         dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3791         if(completely_air)
3792                 dstream<<"[completely air] ";
3793         dstream<<std::endl;
3794 #endif
3795
3796         /*
3797                 Create a packet with the block in the right format
3798         */
3799         
3800         std::ostringstream os(std::ios_base::binary);
3801         block->serialize(os, ver);
3802         std::string s = os.str();
3803         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3804
3805         u32 replysize = 8 + blockdata.getSize();
3806         SharedBuffer<u8> reply(replysize);
3807         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3808         writeS16(&reply[2], p.X);
3809         writeS16(&reply[4], p.Y);
3810         writeS16(&reply[6], p.Z);
3811         memcpy(&reply[8], *blockdata, blockdata.getSize());
3812
3813         /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3814                         <<":  \tpacket size: "<<replysize<<std::endl;*/
3815         
3816         /*
3817                 Send packet
3818         */
3819         m_con.Send(peer_id, 1, reply, true);
3820 }
3821
3822 void Server::SendBlocks(float dtime)
3823 {
3824         DSTACK(__FUNCTION_NAME);
3825
3826         JMutexAutoLock envlock(m_env_mutex);
3827         JMutexAutoLock conlock(m_con_mutex);
3828
3829         //TimeTaker timer("Server::SendBlocks");
3830
3831         core::array<PrioritySortedBlockTransfer> queue;
3832
3833         s32 total_sending = 0;
3834         
3835         {
3836                 ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
3837
3838                 for(core::map<u16, RemoteClient*>::Iterator
3839                         i = m_clients.getIterator();
3840                         i.atEnd() == false; i++)
3841                 {
3842                         RemoteClient *client = i.getNode()->getValue();
3843                         assert(client->peer_id == i.getNode()->getKey());
3844
3845                         total_sending += client->SendingCount();
3846                         
3847                         if(client->serialization_version == SER_FMT_VER_INVALID)
3848                                 continue;
3849                         
3850                         client->GetNextBlocks(this, dtime, queue);
3851                 }
3852         }
3853
3854         // Sort.
3855         // Lowest priority number comes first.
3856         // Lowest is most important.
3857         queue.sort();
3858
3859         for(u32 i=0; i<queue.size(); i++)
3860         {
3861                 //TODO: Calculate limit dynamically
3862                 if(total_sending >= g_settings.getS32
3863                                 ("max_simultaneous_block_sends_server_total"))
3864                         break;
3865                 
3866                 PrioritySortedBlockTransfer q = queue[i];
3867
3868                 MapBlock *block = NULL;
3869                 try
3870                 {
3871                         block = m_env.getMap().getBlockNoCreate(q.pos);
3872                 }
3873                 catch(InvalidPositionException &e)
3874                 {
3875                         continue;
3876                 }
3877
3878                 RemoteClient *client = getClient(q.peer_id);
3879
3880                 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3881
3882                 client->SentBlock(q.pos);
3883
3884                 total_sending++;
3885         }
3886 }
3887
3888 /*
3889         Something random
3890 */
3891
3892 void Server::UpdateCrafting(u16 peer_id)
3893 {
3894         DSTACK(__FUNCTION_NAME);
3895         
3896         Player* player = m_env.getPlayer(peer_id);
3897         assert(player);
3898
3899         /*
3900                 Calculate crafting stuff
3901         */
3902         if(g_settings.getBool("creative_mode") == false)
3903         {
3904                 InventoryList *clist = player->inventory.getList("craft");
3905                 InventoryList *rlist = player->inventory.getList("craftresult");
3906
3907                 if(rlist->getUsedSlots() == 0)
3908                         player->craftresult_is_preview = true;
3909
3910                 if(rlist && player->craftresult_is_preview)
3911                 {
3912                         rlist->clearItems();
3913                 }
3914                 if(clist && rlist && player->craftresult_is_preview)
3915                 {
3916                         InventoryItem *items[9];
3917                         for(u16 i=0; i<9; i++)
3918                         {
3919                                 items[i] = clist->getItem(i);
3920                         }
3921                         
3922                         // Get result of crafting grid
3923                         InventoryItem *result = craft_get_result(items);
3924                         if(result)
3925                                 rlist->addItem(result);
3926                 }
3927         
3928         } // if creative_mode == false
3929 }
3930
3931 RemoteClient* Server::getClient(u16 peer_id)
3932 {
3933         DSTACK(__FUNCTION_NAME);
3934         //JMutexAutoLock lock(m_con_mutex);
3935         core::map<u16, RemoteClient*>::Node *n;
3936         n = m_clients.find(peer_id);
3937         // A client should exist for all peers
3938         assert(n != NULL);
3939         return n->getValue();
3940 }
3941
3942 std::wstring Server::getStatusString()
3943 {
3944         std::wostringstream os(std::ios_base::binary);
3945         os<<L"# Server: ";
3946         // Version
3947         os<<L"version="<<narrow_to_wide(VERSION_STRING);
3948         // Uptime
3949         os<<L", uptime="<<m_uptime.get();
3950         // Information about clients
3951         os<<L", clients={";
3952         for(core::map<u16, RemoteClient*>::Iterator
3953                 i = m_clients.getIterator();
3954                 i.atEnd() == false; i++)
3955         {
3956                 // Get client and check that it is valid
3957                 RemoteClient *client = i.getNode()->getValue();
3958                 assert(client->peer_id == i.getNode()->getKey());
3959                 if(client->serialization_version == SER_FMT_VER_INVALID)
3960                         continue;
3961                 // Get player
3962                 Player *player = m_env.getPlayer(client->peer_id);
3963                 // Get name of player
3964                 std::wstring name = L"unknown";
3965                 if(player != NULL)
3966                         name = narrow_to_wide(player->getName());
3967                 // Add name to information string
3968                 os<<name<<L",";
3969         }
3970         os<<L"}";
3971         if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
3972                 os<<" WARNING: Map saving is disabled."<<std::endl;
3973         return os.str();
3974 }
3975
3976 v3f findSpawnPos(ServerMap &map)
3977 {
3978         //return v3f(50,50,50)*BS;
3979
3980         v2s16 nodepos;
3981         s16 groundheight = 0;
3982         
3983 #if 0
3984         nodepos = v2s16(0,0);
3985         groundheight = 20;
3986 #endif
3987
3988 #if 1
3989         // Try to find a good place a few times
3990         for(s32 i=0; i<1000; i++)
3991         {
3992                 s32 range = 1 + i;
3993                 // We're going to try to throw the player to this position
3994                 nodepos = v2s16(-range + (myrand()%(range*2)),
3995                                 -range + (myrand()%(range*2)));
3996                 v2s16 sectorpos = getNodeSectorPos(nodepos);
3997                 // Get sector (NOTE: Don't get because it's slow)
3998                 //m_env.getMap().emergeSector(sectorpos);
3999                 // Get ground height at point (fallbacks to heightmap function)
4000                 groundheight = map.findGroundLevel(nodepos);
4001                 // Don't go underwater
4002                 if(groundheight < WATER_LEVEL)
4003                 {
4004                         //dstream<<"-> Underwater"<<std::endl;
4005                         continue;
4006                 }
4007                 // Don't go to high places
4008                 if(groundheight > WATER_LEVEL + 4)
4009                 {
4010                         //dstream<<"-> Underwater"<<std::endl;
4011                         continue;
4012                 }
4013
4014                 // Found a good place
4015                 //dstream<<"Searched through "<<i<<" places."<<std::endl;
4016                 break;
4017         }
4018 #endif
4019         
4020         // If no suitable place was not found, go above water at least.
4021         if(groundheight < WATER_LEVEL)
4022                 groundheight = WATER_LEVEL;
4023
4024         return intToFloat(v3s16(
4025                         nodepos.X,
4026                         groundheight + 3,
4027                         nodepos.Y
4028                         ), BS);
4029 }
4030
4031 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4032 {
4033         /*
4034                 Try to get an existing player
4035         */
4036         Player *player = m_env.getPlayer(name);
4037         if(player != NULL)
4038         {
4039                 // If player is already connected, cancel
4040                 if(player->peer_id != 0)
4041                 {
4042                         dstream<<"emergePlayer(): Player already connected"<<std::endl;
4043                         return NULL;
4044                 }
4045
4046                 // Got one.
4047                 player->peer_id = peer_id;
4048                 
4049                 // Reset inventory to creative if in creative mode
4050                 if(g_settings.getBool("creative_mode"))
4051                 {
4052                         craft_set_creative_inventory(player);
4053                 }
4054
4055                 return player;
4056         }
4057
4058         /*
4059                 If player with the wanted peer_id already exists, cancel.
4060         */
4061         if(m_env.getPlayer(peer_id) != NULL)
4062         {
4063                 dstream<<"emergePlayer(): Player with wrong name but same"
4064                                 " peer_id already exists"<<std::endl;
4065                 return NULL;
4066         }
4067         
4068         /*
4069                 Create a new player
4070         */
4071         {
4072                 player = new ServerRemotePlayer();
4073                 //player->peer_id = c.peer_id;
4074                 //player->peer_id = PEER_ID_INEXISTENT;
4075                 player->peer_id = peer_id;
4076                 player->updateName(name);
4077                 m_authmanager.add(name);
4078                 m_authmanager.setPassword(name, password);
4079                 m_authmanager.setPrivs(name,
4080                                 stringToPrivs(g_settings.get("default_privs")));
4081
4082                 /*
4083                         Set player position
4084                 */
4085                 
4086                 dstream<<"Server: Finding spawn place for player \""
4087                                 <<player->getName()<<"\""<<std::endl;
4088
4089                 v3f pos = findSpawnPos(m_env.getServerMap());
4090
4091                 player->setPosition(pos);
4092
4093                 /*
4094                         Add player to environment
4095                 */
4096
4097                 m_env.addPlayer(player);
4098
4099                 /*
4100                         Add stuff to inventory
4101                 */
4102                 
4103                 if(g_settings.getBool("creative_mode"))
4104                 {
4105                         craft_set_creative_inventory(player);
4106                 }
4107                 else if(g_settings.getBool("give_initial_stuff"))
4108                 {
4109                         craft_give_initial_stuff(player);
4110                 }
4111
4112                 return player;
4113                 
4114         } // create new player
4115 }
4116
4117 void Server::handlePeerChange(PeerChange &c)
4118 {
4119         JMutexAutoLock envlock(m_env_mutex);
4120         JMutexAutoLock conlock(m_con_mutex);
4121         
4122         if(c.type == PEER_ADDED)
4123         {
4124                 /*
4125                         Add
4126                 */
4127
4128                 // Error check
4129                 core::map<u16, RemoteClient*>::Node *n;
4130                 n = m_clients.find(c.peer_id);
4131                 // The client shouldn't already exist
4132                 assert(n == NULL);
4133
4134                 // Create client
4135                 RemoteClient *client = new RemoteClient();
4136                 client->peer_id = c.peer_id;
4137                 m_clients.insert(client->peer_id, client);
4138
4139         } // PEER_ADDED
4140         else if(c.type == PEER_REMOVED)
4141         {
4142                 /*
4143                         Delete
4144                 */
4145
4146                 // Error check
4147                 core::map<u16, RemoteClient*>::Node *n;
4148                 n = m_clients.find(c.peer_id);
4149                 // The client should exist
4150                 assert(n != NULL);
4151                 
4152                 /*
4153                         Mark objects to be not known by the client
4154                 */
4155                 RemoteClient *client = n->getValue();
4156                 // Handle objects
4157                 for(core::map<u16, bool>::Iterator
4158                                 i = client->m_known_objects.getIterator();
4159                                 i.atEnd()==false; i++)
4160                 {
4161                         // Get object
4162                         u16 id = i.getNode()->getKey();
4163                         ServerActiveObject* obj = m_env.getActiveObject(id);
4164                         
4165                         if(obj && obj->m_known_by_count > 0)
4166                                 obj->m_known_by_count--;
4167                 }
4168
4169                 // Collect information about leaving in chat
4170                 std::wstring message;
4171                 {
4172                         std::wstring name = L"unknown";
4173                         Player *player = m_env.getPlayer(c.peer_id);
4174                         if(player != NULL)
4175                                 name = narrow_to_wide(player->getName());
4176                         
4177                         message += L"*** ";
4178                         message += name;
4179                         message += L" left game";
4180                         if(c.timeout)
4181                                 message += L" (timed out)";
4182                 }
4183
4184                 /*// Delete player
4185                 {
4186                         m_env.removePlayer(c.peer_id);
4187                 }*/
4188
4189                 // Set player client disconnected
4190                 {
4191                         Player *player = m_env.getPlayer(c.peer_id);
4192                         if(player != NULL)
4193                                 player->peer_id = 0;
4194                 }
4195                 
4196                 // Delete client
4197                 delete m_clients[c.peer_id];
4198                 m_clients.remove(c.peer_id);
4199
4200                 // Send player info to all remaining clients
4201                 SendPlayerInfos();
4202                 
4203                 // Send leave chat message to all remaining clients
4204                 BroadcastChatMessage(message);
4205                 
4206         } // PEER_REMOVED
4207         else
4208         {
4209                 assert(0);
4210         }
4211 }
4212
4213 void Server::handlePeerChanges()
4214 {
4215         while(m_peer_change_queue.size() > 0)
4216         {
4217                 PeerChange c = m_peer_change_queue.pop_front();
4218
4219                 dout_server<<"Server: Handling peer change: "
4220                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4221                                 <<std::endl;
4222
4223                 handlePeerChange(c);
4224         }
4225 }
4226
4227 u64 Server::getPlayerPrivs(Player *player)
4228 {
4229         if(player==NULL)
4230                 return 0;
4231         std::string playername = player->getName();
4232         // Local player gets all privileges regardless of
4233         // what's set on their account.
4234         if(g_settings.get("name") == playername)
4235         {
4236                 return PRIV_ALL;
4237         }
4238         else
4239         {
4240                 return getPlayerAuthPrivs(playername);
4241         }
4242 }
4243
4244 void dedicated_server_loop(Server &server, bool &kill)
4245 {
4246         DSTACK(__FUNCTION_NAME);
4247         
4248         dstream<<DTIME<<std::endl;
4249         dstream<<"========================"<<std::endl;
4250         dstream<<"Running dedicated server"<<std::endl;
4251         dstream<<"========================"<<std::endl;
4252         dstream<<std::endl;
4253
4254         IntervalLimiter m_profiler_interval;
4255
4256         for(;;)
4257         {
4258                 // This is kind of a hack but can be done like this
4259                 // because server.step() is very light
4260                 {
4261                         ScopeProfiler sp(&g_profiler, "dedicated server sleep");
4262                         sleep_ms(30);
4263                 }
4264                 server.step(0.030);
4265
4266                 if(server.getShutdownRequested() || kill)
4267                 {
4268                         dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4269                         break;
4270                 }
4271
4272                 /*
4273                         Profiler
4274                 */
4275                 float profiler_print_interval =
4276                                 g_settings.getFloat("profiler_print_interval");
4277                 if(profiler_print_interval != 0)
4278                 {
4279                         if(m_profiler_interval.step(0.030, profiler_print_interval))
4280                         {
4281                                 dstream<<"Profiler:"<<std::endl;
4282                                 g_profiler.print(dstream);
4283                                 g_profiler.clear();
4284                         }
4285                 }
4286                 
4287                 /*
4288                         Player info
4289                 */
4290                 static int counter = 0;
4291                 counter--;
4292                 if(counter <= 0)
4293                 {
4294                         counter = 10;
4295
4296                         core::list<PlayerInfo> list = server.getPlayerInfo();
4297                         core::list<PlayerInfo>::Iterator i;
4298                         static u32 sum_old = 0;
4299                         u32 sum = PIChecksum(list);
4300                         if(sum != sum_old)
4301                         {
4302                                 dstream<<DTIME<<"Player info:"<<std::endl;
4303                                 for(i=list.begin(); i!=list.end(); i++)
4304                                 {
4305                                         i->PrintLine(&dstream);
4306                                 }
4307                         }
4308                         sum_old = sum;
4309                 }
4310         }
4311 }
4312
4313