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