]> git.lizzy.rs Git - minetest.git/blob - src/server.cpp
Made picking items up in creative mode delete them (because they usually are in the...
[minetest.git] / src / server.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "server.h"
21 #include "utility.h"
22 #include <iostream>
23 #include "clientserver.h"
24 #include "map.h"
25 #include "jmutexautolock.h"
26 #include "main.h"
27 #include "constants.h"
28 #include "voxel.h"
29 #include "materials.h"
30 #include "mineral.h"
31 #include "config.h"
32 #include "servercommand.h"
33 #include "filesys.h"
34 #include "content_mapnode.h"
35 #include "content_craft.h"
36 #include "content_nodemeta.h"
37 #include "mapblock.h"
38 #include "serverobject.h"
39
40 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
41
42 class MapEditEventIgnorer
43 {
44 public:
45         MapEditEventIgnorer(bool *flag):
46                 m_flag(flag)
47         {
48                 if(*m_flag == false)
49                         *m_flag = true;
50                 else
51                         m_flag = NULL;
52         }
53
54         ~MapEditEventIgnorer()
55         {
56                 if(m_flag)
57                 {
58                         assert(*m_flag);
59                         *m_flag = false;
60                 }
61         }
62         
63 private:
64         bool *m_flag;
65 };
66
67 void * ServerThread::Thread()
68 {
69         ThreadStarted();
70
71         DSTACK(__FUNCTION_NAME);
72
73         BEGIN_DEBUG_EXCEPTION_HANDLER
74
75         while(getRun())
76         {
77                 try{
78                         //TimeTaker timer("AsyncRunStep() + Receive()");
79
80                         {
81                                 //TimeTaker timer("AsyncRunStep()");
82                                 m_server->AsyncRunStep();
83                         }
84                 
85                         //dout_server<<"Running m_server->Receive()"<<std::endl;
86                         m_server->Receive();
87                 }
88                 catch(con::NoIncomingDataException &e)
89                 {
90                 }
91                 catch(con::PeerNotFoundException &e)
92                 {
93                         dout_server<<"Server: PeerNotFoundException"<<std::endl;
94                 }
95         }
96         
97         END_DEBUG_EXCEPTION_HANDLER
98
99         return NULL;
100 }
101
102 void * EmergeThread::Thread()
103 {
104         ThreadStarted();
105
106         DSTACK(__FUNCTION_NAME);
107
108         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                 // Skip if object has been removed
2372                 if(obj->m_removed)
2373                         return;
2374                 
2375                 //TODO: Check that object is reasonably close
2376                 
2377                 // Left click, pick object up (usually)
2378                 if(button == 0)
2379                 {
2380                         /*
2381                                 Try creating inventory item
2382                         */
2383                         InventoryItem *item = obj->createPickedUpItem();
2384                         
2385                         if(item)
2386                         {
2387                                 InventoryList *ilist = player->inventory.getList("main");
2388                                 if(ilist != NULL)
2389                                 {
2390                                         if(g_settings.getBool("creative_mode") == false)
2391                                         {
2392                                                 // Skip if inventory has no free space
2393                                                 if(ilist->getUsedSlots() == ilist->getSize())
2394                                                 {
2395                                                         dout_server<<"Player inventory has no free space"<<std::endl;
2396                                                         return;
2397                                                 }
2398
2399                                                 // Add to inventory and send inventory
2400                                                 ilist->addItem(item);
2401                                                 UpdateCrafting(player->peer_id);
2402                                                 SendInventory(player->peer_id);
2403                                         }
2404
2405                                         // Remove object from environment
2406                                         obj->m_removed = true;
2407                                 }
2408                         }
2409                         else
2410                         {
2411                                 /*
2412                                         Item cannot be picked up. Punch it instead.
2413                                 */
2414
2415                                 ToolItem *titem = NULL;
2416                                 std::string toolname = "";
2417
2418                                 InventoryList *mlist = player->inventory.getList("main");
2419                                 if(mlist != NULL)
2420                                 {
2421                                         InventoryItem *item = mlist->getItem(item_i);
2422                                         if(item && (std::string)item->getName() == "ToolItem")
2423                                         {
2424                                                 titem = (ToolItem*)item;
2425                                                 toolname = titem->getToolName();
2426                                         }
2427                                 }
2428
2429                                 v3f playerpos = player->getPosition();
2430                                 v3f objpos = obj->getBasePosition();
2431                                 v3f dir = (objpos - playerpos).normalize();
2432                                 
2433                                 u16 wear = obj->punch(toolname, dir);
2434                                 
2435                                 if(titem)
2436                                 {
2437                                         bool weared_out = titem->addWear(wear);
2438                                         if(weared_out)
2439                                                 mlist->deleteItem(item_i);
2440                                         SendInventory(player->peer_id);
2441                                 }
2442                         }
2443                 }
2444                 // Right click, do something with object
2445                 if(button == 1)
2446                 {
2447                         // Track hp changes super-crappily
2448                         u16 oldhp = player->hp;
2449                         
2450                         // Do stuff
2451                         obj->rightClick(player);
2452                         
2453                         // Send back stuff
2454                         if(player->hp != oldhp)
2455                         {
2456                                 SendPlayerHP(player);
2457                         }
2458                 }
2459         }
2460         else if(command == TOSERVER_GROUND_ACTION)
2461         {
2462                 if(datasize < 17)
2463                         return;
2464                 /*
2465                         length: 17
2466                         [0] u16 command
2467                         [2] u8 action
2468                         [3] v3s16 nodepos_undersurface
2469                         [9] v3s16 nodepos_abovesurface
2470                         [15] u16 item
2471                         actions:
2472                         0: start digging
2473                         1: place block
2474                         2: stop digging (all parameters ignored)
2475                         3: digging completed
2476                 */
2477                 u8 action = readU8(&data[2]);
2478                 v3s16 p_under;
2479                 p_under.X = readS16(&data[3]);
2480                 p_under.Y = readS16(&data[5]);
2481                 p_under.Z = readS16(&data[7]);
2482                 v3s16 p_over;
2483                 p_over.X = readS16(&data[9]);
2484                 p_over.Y = readS16(&data[11]);
2485                 p_over.Z = readS16(&data[13]);
2486                 u16 item_i = readU16(&data[15]);
2487
2488                 //TODO: Check that target is reasonably close
2489                 
2490                 /*
2491                         0: start digging
2492                 */
2493                 if(action == 0)
2494                 {
2495                         /*
2496                                 NOTE: This can be used in the future to check if
2497                                 somebody is cheating, by checking the timing.
2498                         */
2499                 } // action == 0
2500
2501                 /*
2502                         2: stop digging
2503                 */
2504                 else if(action == 2)
2505                 {
2506 #if 0
2507                         RemoteClient *client = getClient(peer->id);
2508                         JMutexAutoLock digmutex(client->m_dig_mutex);
2509                         client->m_dig_tool_item = -1;
2510 #endif
2511                 }
2512
2513                 /*
2514                         3: Digging completed
2515                 */
2516                 else if(action == 3)
2517                 {
2518                         // Mandatory parameter; actually used for nothing
2519                         core::map<v3s16, MapBlock*> modified_blocks;
2520
2521                         content_t material = CONTENT_IGNORE;
2522                         u8 mineral = MINERAL_NONE;
2523
2524                         bool cannot_remove_node = false;
2525
2526                         try
2527                         {
2528                                 MapNode n = m_env.getMap().getNode(p_under);
2529                                 // Get mineral
2530                                 mineral = n.getMineral();
2531                                 // Get material at position
2532                                 material = n.getContent();
2533                                 // If not yet cancelled
2534                                 if(cannot_remove_node == false)
2535                                 {
2536                                         // If it's not diggable, do nothing
2537                                         if(content_diggable(material) == false)
2538                                         {
2539                                                 derr_server<<"Server: Not finishing digging: "
2540                                                                 <<"Node not diggable"
2541                                                                 <<std::endl;
2542                                                 cannot_remove_node = true;
2543                                         }
2544                                 }
2545                                 // If not yet cancelled
2546                                 if(cannot_remove_node == false)
2547                                 {
2548                                         // Get node metadata
2549                                         NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2550                                         if(meta && meta->nodeRemovalDisabled() == true)
2551                                         {
2552                                                 derr_server<<"Server: Not finishing digging: "
2553                                                                 <<"Node metadata disables removal"
2554                                                                 <<std::endl;
2555                                                 cannot_remove_node = true;
2556                                         }
2557                                 }
2558                         }
2559                         catch(InvalidPositionException &e)
2560                         {
2561                                 derr_server<<"Server: Not finishing digging: Node not found."
2562                                                 <<" Adding block to emerge queue."
2563                                                 <<std::endl;
2564                                 m_emerge_queue.addBlock(peer_id,
2565                                                 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2566                                 cannot_remove_node = true;
2567                         }
2568
2569                         // Make sure the player is allowed to do it
2570                         if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2571                         {
2572                                 dstream<<"Player "<<player->getName()<<" cannot remove node"
2573                                                 <<" because privileges are "<<getPlayerPrivs(player)
2574                                                 <<std::endl;
2575                                 cannot_remove_node = true;
2576                         }
2577
2578                         /*
2579                                 If node can't be removed, set block to be re-sent to
2580                                 client and quit.
2581                         */
2582                         if(cannot_remove_node)
2583                         {
2584                                 derr_server<<"Server: Not finishing digging."<<std::endl;
2585
2586                                 // Client probably has wrong data.
2587                                 // Set block not sent, so that client will get
2588                                 // a valid one.
2589                                 dstream<<"Client "<<peer_id<<" tried to dig "
2590                                                 <<"node; but node cannot be removed."
2591                                                 <<" setting MapBlock not sent."<<std::endl;
2592                                 RemoteClient *client = getClient(peer_id);
2593                                 v3s16 blockpos = getNodeBlockPos(p_under);
2594                                 client->SetBlockNotSent(blockpos);
2595                                         
2596                                 return;
2597                         }
2598                         
2599                         /*
2600                                 Send the removal to all close-by players.
2601                                 - If other player is close, send REMOVENODE
2602                                 - Otherwise set blocks not sent
2603                         */
2604                         core::list<u16> far_players;
2605                         sendRemoveNode(p_under, peer_id, &far_players, 30);
2606                         
2607                         /*
2608                                 Update and send inventory
2609                         */
2610
2611                         if(g_settings.getBool("creative_mode") == false)
2612                         {
2613                                 /*
2614                                         Wear out tool
2615                                 */
2616                                 InventoryList *mlist = player->inventory.getList("main");
2617                                 if(mlist != NULL)
2618                                 {
2619                                         InventoryItem *item = mlist->getItem(item_i);
2620                                         if(item && (std::string)item->getName() == "ToolItem")
2621                                         {
2622                                                 ToolItem *titem = (ToolItem*)item;
2623                                                 std::string toolname = titem->getToolName();
2624
2625                                                 // Get digging properties for material and tool
2626                                                 DiggingProperties prop =
2627                                                                 getDiggingProperties(material, toolname);
2628
2629                                                 if(prop.diggable == false)
2630                                                 {
2631                                                         derr_server<<"Server: WARNING: Player digged"
2632                                                                         <<" with impossible material + tool"
2633                                                                         <<" combination"<<std::endl;
2634                                                 }
2635                                                 
2636                                                 bool weared_out = titem->addWear(prop.wear);
2637
2638                                                 if(weared_out)
2639                                                 {
2640                                                         mlist->deleteItem(item_i);
2641                                                 }
2642                                         }
2643                                 }
2644
2645                                 /*
2646                                         Add dug item to inventory
2647                                 */
2648
2649                                 InventoryItem *item = NULL;
2650
2651                                 if(mineral != MINERAL_NONE)
2652                                         item = getDiggedMineralItem(mineral);
2653                                 
2654                                 // If not mineral
2655                                 if(item == NULL)
2656                                 {
2657                                         std::string &dug_s = content_features(material).dug_item;
2658                                         if(dug_s != "")
2659                                         {
2660                                                 std::istringstream is(dug_s, std::ios::binary);
2661                                                 item = InventoryItem::deSerialize(is);
2662                                         }
2663                                 }
2664                                 
2665                                 if(item != NULL)
2666                                 {
2667                                         // Add a item to inventory
2668                                         player->inventory.addItem("main", item);
2669
2670                                         // Send inventory
2671                                         UpdateCrafting(player->peer_id);
2672                                         SendInventory(player->peer_id);
2673                                 }
2674                         }
2675
2676                         /*
2677                                 Remove the node
2678                                 (this takes some time so it is done after the quick stuff)
2679                         */
2680                         {
2681                                 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2682
2683                                 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2684                         }
2685                         /*
2686                                 Set blocks not sent to far players
2687                         */
2688                         for(core::list<u16>::Iterator
2689                                         i = far_players.begin();
2690                                         i != far_players.end(); i++)
2691                         {
2692                                 u16 peer_id = *i;
2693                                 RemoteClient *client = getClient(peer_id);
2694                                 if(client==NULL)
2695                                         continue;
2696                                 client->SetBlocksNotSent(modified_blocks);
2697                         }
2698                 }
2699                 
2700                 /*
2701                         1: place block
2702                 */
2703                 else if(action == 1)
2704                 {
2705
2706                         InventoryList *ilist = player->inventory.getList("main");
2707                         if(ilist == NULL)
2708                                 return;
2709
2710                         // Get item
2711                         InventoryItem *item = ilist->getItem(item_i);
2712                         
2713                         // If there is no item, it is not possible to add it anywhere
2714                         if(item == NULL)
2715                                 return;
2716                         
2717                         /*
2718                                 Handle material items
2719                         */
2720                         if(std::string("MaterialItem") == item->getName())
2721                         {
2722                                 try{
2723                                         // Don't add a node if this is not a free space
2724                                         MapNode n2 = m_env.getMap().getNode(p_over);
2725                                         bool no_enough_privs =
2726                                                         ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2727                                         if(no_enough_privs)
2728                                                 dstream<<"Player "<<player->getName()<<" cannot add node"
2729                                                         <<" because privileges are "<<getPlayerPrivs(player)
2730                                                         <<std::endl;
2731
2732                                         if(content_features(n2).buildable_to == false
2733                                                 || no_enough_privs)
2734                                         {
2735                                                 // Client probably has wrong data.
2736                                                 // Set block not sent, so that client will get
2737                                                 // a valid one.
2738                                                 dstream<<"Client "<<peer_id<<" tried to place"
2739                                                                 <<" node in invalid position; setting"
2740                                                                 <<" MapBlock not sent."<<std::endl;
2741                                                 RemoteClient *client = getClient(peer_id);
2742                                                 v3s16 blockpos = getNodeBlockPos(p_over);
2743                                                 client->SetBlockNotSent(blockpos);
2744                                                 return;
2745                                         }
2746                                 }
2747                                 catch(InvalidPositionException &e)
2748                                 {
2749                                         derr_server<<"Server: Ignoring ADDNODE: Node not found"
2750                                                         <<" Adding block to emerge queue."
2751                                                         <<std::endl;
2752                                         m_emerge_queue.addBlock(peer_id,
2753                                                         getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2754                                         return;
2755                                 }
2756
2757                                 // Reset build time counter
2758                                 getClient(peer->id)->m_time_from_building = 0.0;
2759                                 
2760                                 // Create node data
2761                                 MaterialItem *mitem = (MaterialItem*)item;
2762                                 MapNode n;
2763                                 n.setContent(mitem->getMaterial());
2764
2765                                 // Calculate direction for wall mounted stuff
2766                                 if(content_features(n).wall_mounted)
2767                                         n.param2 = packDir(p_under - p_over);
2768
2769                                 // Calculate the direction for furnaces and chests and stuff
2770                                 if(content_features(n).param_type == CPT_FACEDIR_SIMPLE)
2771                                 {
2772                                         v3f playerpos = player->getPosition();
2773                                         v3f blockpos = intToFloat(p_over, BS) - playerpos;
2774                                         blockpos = blockpos.normalize();
2775                                         n.param1 = 0;
2776                                         if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2777                                                 if (blockpos.X < 0)
2778                                                         n.param1 = 3;
2779                                                 else
2780                                                         n.param1 = 1;
2781                                         } else {
2782                                                 if (blockpos.Z < 0)
2783                                                         n.param1 = 2;
2784                                                 else
2785                                                         n.param1 = 0;
2786                                         }
2787                                 }
2788
2789                                 /*
2790                                         Send to all close-by players
2791                                 */
2792                                 core::list<u16> far_players;
2793                                 sendAddNode(p_over, n, 0, &far_players, 30);
2794                                 
2795                                 /*
2796                                         Handle inventory
2797                                 */
2798                                 InventoryList *ilist = player->inventory.getList("main");
2799                                 if(g_settings.getBool("creative_mode") == false && ilist)
2800                                 {
2801                                         // Remove from inventory and send inventory
2802                                         if(mitem->getCount() == 1)
2803                                                 ilist->deleteItem(item_i);
2804                                         else
2805                                                 mitem->remove(1);
2806                                         // Send inventory
2807                                         UpdateCrafting(peer_id);
2808                                         SendInventory(peer_id);
2809                                 }
2810                                 
2811                                 /*
2812                                         Add node.
2813
2814                                         This takes some time so it is done after the quick stuff
2815                                 */
2816                                 core::map<v3s16, MapBlock*> modified_blocks;
2817                                 {
2818                                         MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2819
2820                                         m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2821                                 }
2822                                 /*
2823                                         Set blocks not sent to far players
2824                                 */
2825                                 for(core::list<u16>::Iterator
2826                                                 i = far_players.begin();
2827                                                 i != far_players.end(); i++)
2828                                 {
2829                                         u16 peer_id = *i;
2830                                         RemoteClient *client = getClient(peer_id);
2831                                         if(client==NULL)
2832                                                 continue;
2833                                         client->SetBlocksNotSent(modified_blocks);
2834                                 }
2835
2836                                 /*
2837                                         Calculate special events
2838                                 */
2839                                 
2840                                 /*if(n.d == CONTENT_MESE)
2841                                 {
2842                                         u32 count = 0;
2843                                         for(s16 z=-1; z<=1; z++)
2844                                         for(s16 y=-1; y<=1; y++)
2845                                         for(s16 x=-1; x<=1; x++)
2846                                         {
2847                                                 
2848                                         }
2849                                 }*/
2850                         }
2851                         /*
2852                                 Place other item (not a block)
2853                         */
2854                         else
2855                         {
2856                                 v3s16 blockpos = getNodeBlockPos(p_over);
2857                                 
2858                                 /*
2859                                         Check that the block is loaded so that the item
2860                                         can properly be added to the static list too
2861                                 */
2862                                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2863                                 if(block==NULL)
2864                                 {
2865                                         derr_server<<"Error while placing object: "
2866                                                         "block not found"<<std::endl;
2867                                         return;
2868                                 }
2869
2870                                 dout_server<<"Placing a miscellaneous item on map"
2871                                                 <<std::endl;
2872                                 
2873                                 // Calculate a position for it
2874                                 v3f pos = intToFloat(p_over, BS);
2875                                 //pos.Y -= BS*0.45;
2876                                 pos.Y -= BS*0.25; // let it drop a bit
2877                                 // Randomize a bit
2878                                 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2879                                 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2880
2881                                 /*
2882                                         Create the object
2883                                 */
2884                                 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2885
2886                                 if(obj == NULL)
2887                                 {
2888                                         derr_server<<"WARNING: item resulted in NULL object, "
2889                                                         <<"not placing onto map"
2890                                                         <<std::endl;
2891                                 }
2892                                 else
2893                                 {
2894                                         // Add the object to the environment
2895                                         m_env.addActiveObject(obj);
2896                                         
2897                                         dout_server<<"Placed object"<<std::endl;
2898
2899                                         if(g_settings.getBool("creative_mode") == false)
2900                                         {
2901                                                 // Delete the right amount of items from the slot
2902                                                 u16 dropcount = item->getDropCount();
2903                                                 
2904                                                 // Delete item if all gone
2905                                                 if(item->getCount() <= dropcount)
2906                                                 {
2907                                                         if(item->getCount() < dropcount)
2908                                                                 dstream<<"WARNING: Server: dropped more items"
2909                                                                                 <<" than the slot contains"<<std::endl;
2910                                                         
2911                                                         InventoryList *ilist = player->inventory.getList("main");
2912                                                         if(ilist)
2913                                                                 // Remove from inventory and send inventory
2914                                                                 ilist->deleteItem(item_i);
2915                                                 }
2916                                                 // Else decrement it
2917                                                 else
2918                                                         item->remove(dropcount);
2919                                                 
2920                                                 // Send inventory
2921                                                 UpdateCrafting(peer_id);
2922                                                 SendInventory(peer_id);
2923                                         }
2924                                 }
2925                         }
2926
2927                 } // action == 1
2928
2929                 /*
2930                         Catch invalid actions
2931                 */
2932                 else
2933                 {
2934                         derr_server<<"WARNING: Server: Invalid action "
2935                                         <<action<<std::endl;
2936                 }
2937         }
2938 #if 0
2939         else if(command == TOSERVER_RELEASE)
2940         {
2941                 if(datasize < 3)
2942                         return;
2943                 /*
2944                         length: 3
2945                         [0] u16 command
2946                         [2] u8 button
2947                 */
2948                 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
2949         }
2950 #endif
2951         else if(command == TOSERVER_SIGNTEXT)
2952         {
2953                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2954                         return;
2955                 /*
2956                         u16 command
2957                         v3s16 blockpos
2958                         s16 id
2959                         u16 textlen
2960                         textdata
2961                 */
2962                 std::string datastring((char*)&data[2], datasize-2);
2963                 std::istringstream is(datastring, std::ios_base::binary);
2964                 u8 buf[6];
2965                 // Read stuff
2966                 is.read((char*)buf, 6);
2967                 v3s16 blockpos = readV3S16(buf);
2968                 is.read((char*)buf, 2);
2969                 s16 id = readS16(buf);
2970                 is.read((char*)buf, 2);
2971                 u16 textlen = readU16(buf);
2972                 std::string text;
2973                 for(u16 i=0; i<textlen; i++)
2974                 {
2975                         is.read((char*)buf, 1);
2976                         text += (char)buf[0];
2977                 }
2978
2979                 MapBlock *block = NULL;
2980                 try
2981                 {
2982                         block = m_env.getMap().getBlockNoCreate(blockpos);
2983                 }
2984                 catch(InvalidPositionException &e)
2985                 {
2986                         derr_server<<"Error while setting sign text: "
2987                                         "block not found"<<std::endl;
2988                         return;
2989                 }
2990
2991                 MapBlockObject *obj = block->getObject(id);
2992                 if(obj == NULL)
2993                 {
2994                         derr_server<<"Error while setting sign text: "
2995                                         "object not found"<<std::endl;
2996                         return;
2997                 }
2998                 
2999                 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
3000                 {
3001                         derr_server<<"Error while setting sign text: "
3002                                         "object is not a sign"<<std::endl;
3003                         return;
3004                 }
3005
3006                 ((SignObject*)obj)->setText(text);
3007
3008                 obj->getBlock()->setChangedFlag();
3009         }
3010         else if(command == TOSERVER_SIGNNODETEXT)
3011         {
3012                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3013                         return;
3014                 /*
3015                         u16 command
3016                         v3s16 p
3017                         u16 textlen
3018                         textdata
3019                 */
3020                 std::string datastring((char*)&data[2], datasize-2);
3021                 std::istringstream is(datastring, std::ios_base::binary);
3022                 u8 buf[6];
3023                 // Read stuff
3024                 is.read((char*)buf, 6);
3025                 v3s16 p = readV3S16(buf);
3026                 is.read((char*)buf, 2);
3027                 u16 textlen = readU16(buf);
3028                 std::string text;
3029                 for(u16 i=0; i<textlen; i++)
3030                 {
3031                         is.read((char*)buf, 1);
3032                         text += (char)buf[0];
3033                 }
3034
3035                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3036                 if(!meta)
3037                         return;
3038                 if(meta->typeId() != CONTENT_SIGN_WALL)
3039                         return;
3040                 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
3041                 signmeta->setText(text);
3042                 
3043                 v3s16 blockpos = getNodeBlockPos(p);
3044                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
3045                 if(block)
3046                 {
3047                         block->setChangedFlag();
3048                 }
3049
3050                 for(core::map<u16, RemoteClient*>::Iterator
3051                         i = m_clients.getIterator();
3052                         i.atEnd()==false; i++)
3053                 {
3054                         RemoteClient *client = i.getNode()->getValue();
3055                         client->SetBlockNotSent(blockpos);
3056                 }
3057         }
3058         else if(command == TOSERVER_INVENTORY_ACTION)
3059         {
3060                 /*// Ignore inventory changes if in creative mode
3061                 if(g_settings.getBool("creative_mode") == true)
3062                 {
3063                         dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3064                                         <<std::endl;
3065                         return;
3066                 }*/
3067                 // Strip command and create a stream
3068                 std::string datastring((char*)&data[2], datasize-2);
3069                 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3070                 std::istringstream is(datastring, std::ios_base::binary);
3071                 // Create an action
3072                 InventoryAction *a = InventoryAction::deSerialize(is);
3073                 if(a != NULL)
3074                 {
3075                         // Create context
3076                         InventoryContext c;
3077                         c.current_player = player;
3078
3079                         /*
3080                                 Handle craftresult specially if not in creative mode
3081                         */
3082                         bool disable_action = false;
3083                         if(a->getType() == IACTION_MOVE
3084                                         && g_settings.getBool("creative_mode") == false)
3085                         {
3086                                 IMoveAction *ma = (IMoveAction*)a;
3087                                 if(ma->to_inv == "current_player" &&
3088                                                 ma->from_inv == "current_player")
3089                                 {
3090                                         InventoryList *rlist = player->inventory.getList("craftresult");
3091                                         assert(rlist);
3092                                         InventoryList *clist = player->inventory.getList("craft");
3093                                         assert(clist);
3094                                         InventoryList *mlist = player->inventory.getList("main");
3095                                         assert(mlist);
3096                                         /*
3097                                                 Craftresult is no longer preview if something
3098                                                 is moved into it
3099                                         */
3100                                         if(ma->to_list == "craftresult"
3101                                                         && ma->from_list != "craftresult")
3102                                         {
3103                                                 // If it currently is a preview, remove
3104                                                 // its contents
3105                                                 if(player->craftresult_is_preview)
3106                                                 {
3107                                                         rlist->deleteItem(0);
3108                                                 }
3109                                                 player->craftresult_is_preview = false;
3110                                         }
3111                                         /*
3112                                                 Crafting takes place if this condition is true.
3113                                         */
3114                                         if(player->craftresult_is_preview &&
3115                                                         ma->from_list == "craftresult")
3116                                         {
3117                                                 player->craftresult_is_preview = false;
3118                                                 clist->decrementMaterials(1);
3119                                         }
3120                                         /*
3121                                                 If the craftresult is placed on itself, move it to
3122                                                 main inventory instead of doing the action
3123                                         */
3124                                         if(ma->to_list == "craftresult"
3125                                                         && ma->from_list == "craftresult")
3126                                         {
3127                                                 disable_action = true;
3128                                                 
3129                                                 InventoryItem *item1 = rlist->changeItem(0, NULL);
3130                                                 mlist->addItem(item1);
3131                                         }
3132                                 }
3133                         }
3134                         
3135                         if(disable_action == false)
3136                         {
3137                                 // Feed action to player inventory
3138                                 a->apply(&c, this);
3139                                 // Eat the action
3140                                 delete a;
3141                         }
3142                         else
3143                         {
3144                                 // Send inventory
3145                                 UpdateCrafting(player->peer_id);
3146                                 SendInventory(player->peer_id);
3147                         }
3148                 }
3149                 else
3150                 {
3151                         dstream<<"TOSERVER_INVENTORY_ACTION: "
3152                                         <<"InventoryAction::deSerialize() returned NULL"
3153                                         <<std::endl;
3154                 }
3155         }
3156         else if(command == TOSERVER_CHAT_MESSAGE)
3157         {
3158                 /*
3159                         u16 command
3160                         u16 length
3161                         wstring message
3162                 */
3163                 u8 buf[6];
3164                 std::string datastring((char*)&data[2], datasize-2);
3165                 std::istringstream is(datastring, std::ios_base::binary);
3166                 
3167                 // Read stuff
3168                 is.read((char*)buf, 2);
3169                 u16 len = readU16(buf);
3170                 
3171                 std::wstring message;
3172                 for(u16 i=0; i<len; i++)
3173                 {
3174                         is.read((char*)buf, 2);
3175                         message += (wchar_t)readU16(buf);
3176                 }
3177
3178                 // Get player name of this client
3179                 std::wstring name = narrow_to_wide(player->getName());
3180                 
3181                 // Line to send to players
3182                 std::wstring line;
3183                 // Whether to send to the player that sent the line
3184                 bool send_to_sender = false;
3185                 // Whether to send to other players
3186                 bool send_to_others = false;
3187                 
3188                 // Local player gets all privileges regardless of
3189                 // what's set on their account.
3190                 u64 privs = getPlayerPrivs(player);
3191
3192                 // Parse commands
3193                 std::wstring commandprefix = L"/#";
3194                 if(message.substr(0, commandprefix.size()) == commandprefix)
3195                 {
3196                         line += L"Server: ";
3197
3198                         message = message.substr(commandprefix.size());
3199
3200                         ServerCommandContext *ctx = new ServerCommandContext(
3201                                 str_split(message, L' '),
3202                                 this,
3203                                 &m_env,
3204                                 player,
3205                                 privs);
3206
3207                         line += processServerCommand(ctx);
3208                         send_to_sender = ctx->flags & 1;
3209                         send_to_others = ctx->flags & 2;
3210                         delete ctx;
3211
3212                 }
3213                 else
3214                 {
3215                         if(privs & PRIV_SHOUT)
3216                         {
3217                                 line += L"<";
3218                                 line += name;
3219                                 line += L"> ";
3220                                 line += message;
3221                                 send_to_others = true;
3222                         }
3223                         else
3224                         {
3225                                 line += L"Server: You are not allowed to shout";
3226                                 send_to_sender = true;
3227                         }
3228                 }
3229                 
3230                 if(line != L"")
3231                 {
3232                         dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3233
3234                         /*
3235                                 Send the message to clients
3236                         */
3237                         for(core::map<u16, RemoteClient*>::Iterator
3238                                 i = m_clients.getIterator();
3239                                 i.atEnd() == false; i++)
3240                         {
3241                                 // Get client and check that it is valid
3242                                 RemoteClient *client = i.getNode()->getValue();
3243                                 assert(client->peer_id == i.getNode()->getKey());
3244                                 if(client->serialization_version == SER_FMT_VER_INVALID)
3245                                         continue;
3246
3247                                 // Filter recipient
3248                                 bool sender_selected = (peer_id == client->peer_id);
3249                                 if(sender_selected == true && send_to_sender == false)
3250                                         continue;
3251                                 if(sender_selected == false && send_to_others == false)
3252                                         continue;
3253
3254                                 SendChatMessage(client->peer_id, line);
3255                         }
3256                 }
3257         }
3258         else if(command == TOSERVER_DAMAGE)
3259         {
3260                 if(g_settings.getBool("enable_damage"))
3261                 {
3262                         std::string datastring((char*)&data[2], datasize-2);
3263                         std::istringstream is(datastring, std::ios_base::binary);
3264                         u8 damage = readU8(is);
3265                         if(player->hp > damage)
3266                         {
3267                                 player->hp -= damage;
3268                         }
3269                         else
3270                         {
3271                                 player->hp = 0;
3272
3273                                 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3274                                                 <<std::endl;
3275                                 
3276                                 v3f pos = findSpawnPos(m_env.getServerMap());
3277                                 player->setPosition(pos);
3278                                 player->hp = 20;
3279                                 SendMovePlayer(player);
3280                                 SendPlayerHP(player);
3281                                 
3282                                 //TODO: Throw items around
3283                         }
3284                 }
3285
3286                 SendPlayerHP(player);
3287         }
3288         else if(command == TOSERVER_PASSWORD)
3289         {
3290                 /*
3291                         [0] u16 TOSERVER_PASSWORD
3292                         [2] u8[28] old password
3293                         [30] u8[28] new password
3294                 */
3295
3296                 if(datasize != 2+PASSWORD_SIZE*2)
3297                         return;
3298                 /*char password[PASSWORD_SIZE];
3299                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3300                         password[i] = data[2+i];
3301                 password[PASSWORD_SIZE-1] = 0;*/
3302                 std::string oldpwd;
3303                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3304                 {
3305                         char c = data[2+i];
3306                         if(c == 0)
3307                                 break;
3308                         oldpwd += c;
3309                 }
3310                 std::string newpwd;
3311                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3312                 {
3313                         char c = data[2+PASSWORD_SIZE+i];
3314                         if(c == 0)
3315                                 break;
3316                         newpwd += c;
3317                 }
3318
3319                 std::string playername = player->getName();
3320
3321                 if(m_authmanager.exists(playername) == false)
3322                 {
3323                         dstream<<"Server: playername not found in authmanager"<<std::endl;
3324                         // Wrong old password supplied!!
3325                         SendChatMessage(peer_id, L"playername not found in authmanager");
3326                         return;
3327                 }
3328
3329                 std::string checkpwd = m_authmanager.getPassword(playername);
3330                 
3331                 if(oldpwd != checkpwd)
3332                 {
3333                         dstream<<"Server: invalid old password"<<std::endl;
3334                         // Wrong old password supplied!!
3335                         SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3336                         return;
3337                 }
3338
3339                 m_authmanager.setPassword(playername, newpwd);
3340                 
3341                 dstream<<"Server: password change successful for "<<playername
3342                                 <<std::endl;
3343                 SendChatMessage(peer_id, L"Password change successful");
3344         }
3345         else
3346         {
3347                 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3348                                 "unknown command "<<command<<std::endl;
3349         }
3350         
3351         } //try
3352         catch(SendFailedException &e)
3353         {
3354                 derr_server<<"Server::ProcessData(): SendFailedException: "
3355                                 <<"what="<<e.what()
3356                                 <<std::endl;
3357         }
3358 }
3359
3360 void Server::onMapEditEvent(MapEditEvent *event)
3361 {
3362         //dstream<<"Server::onMapEditEvent()"<<std::endl;
3363         if(m_ignore_map_edit_events)
3364                 return;
3365         MapEditEvent *e = event->clone();
3366         m_unsent_map_edit_queue.push_back(e);
3367 }
3368
3369 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3370 {
3371         if(id == "current_player")
3372         {
3373                 assert(c->current_player);
3374                 return &(c->current_player->inventory);
3375         }
3376         
3377         Strfnd fn(id);
3378         std::string id0 = fn.next(":");
3379
3380         if(id0 == "nodemeta")
3381         {
3382                 v3s16 p;
3383                 p.X = stoi(fn.next(","));
3384                 p.Y = stoi(fn.next(","));
3385                 p.Z = stoi(fn.next(","));
3386                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3387                 if(meta)
3388                         return meta->getInventory();
3389                 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3390                                 <<"no metadata found"<<std::endl;
3391                 return NULL;
3392         }
3393
3394         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3395         return NULL;
3396 }
3397 void Server::inventoryModified(InventoryContext *c, std::string id)
3398 {
3399         if(id == "current_player")
3400         {
3401                 assert(c->current_player);
3402                 // Send inventory
3403                 UpdateCrafting(c->current_player->peer_id);
3404                 SendInventory(c->current_player->peer_id);
3405                 return;
3406         }
3407         
3408         Strfnd fn(id);
3409         std::string id0 = fn.next(":");
3410
3411         if(id0 == "nodemeta")
3412         {
3413                 v3s16 p;
3414                 p.X = stoi(fn.next(","));
3415                 p.Y = stoi(fn.next(","));
3416                 p.Z = stoi(fn.next(","));
3417                 v3s16 blockpos = getNodeBlockPos(p);
3418
3419                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3420                 if(meta)
3421                         meta->inventoryModified();
3422
3423                 for(core::map<u16, RemoteClient*>::Iterator
3424                         i = m_clients.getIterator();
3425                         i.atEnd()==false; i++)
3426                 {
3427                         RemoteClient *client = i.getNode()->getValue();
3428                         client->SetBlockNotSent(blockpos);
3429                 }
3430
3431                 return;
3432         }
3433
3434         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3435 }
3436
3437 core::list<PlayerInfo> Server::getPlayerInfo()
3438 {
3439         DSTACK(__FUNCTION_NAME);
3440         JMutexAutoLock envlock(m_env_mutex);
3441         JMutexAutoLock conlock(m_con_mutex);
3442         
3443         core::list<PlayerInfo> list;
3444
3445         core::list<Player*> players = m_env.getPlayers();
3446         
3447         core::list<Player*>::Iterator i;
3448         for(i = players.begin();
3449                         i != players.end(); i++)
3450         {
3451                 PlayerInfo info;
3452
3453                 Player *player = *i;
3454
3455                 try{
3456                         con::Peer *peer = m_con.GetPeer(player->peer_id);
3457                         // Copy info from peer to info struct
3458                         info.id = peer->id;
3459                         info.address = peer->address;
3460                         info.avg_rtt = peer->avg_rtt;
3461                 }
3462                 catch(con::PeerNotFoundException &e)
3463                 {
3464                         // Set dummy peer info
3465                         info.id = 0;
3466                         info.address = Address(0,0,0,0,0);
3467                         info.avg_rtt = 0.0;
3468                 }
3469
3470                 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3471                 info.position = player->getPosition();
3472
3473                 list.push_back(info);
3474         }
3475
3476         return list;
3477 }
3478
3479
3480 void Server::peerAdded(con::Peer *peer)
3481 {
3482         DSTACK(__FUNCTION_NAME);
3483         dout_server<<"Server::peerAdded(): peer->id="
3484                         <<peer->id<<std::endl;
3485         
3486         PeerChange c;
3487         c.type = PEER_ADDED;
3488         c.peer_id = peer->id;
3489         c.timeout = false;
3490         m_peer_change_queue.push_back(c);
3491 }
3492
3493 void Server::deletingPeer(con::Peer *peer, bool timeout)
3494 {
3495         DSTACK(__FUNCTION_NAME);
3496         dout_server<<"Server::deletingPeer(): peer->id="
3497                         <<peer->id<<", timeout="<<timeout<<std::endl;
3498         
3499         PeerChange c;
3500         c.type = PEER_REMOVED;
3501         c.peer_id = peer->id;
3502         c.timeout = timeout;
3503         m_peer_change_queue.push_back(c);
3504 }
3505
3506 /*
3507         Static send methods
3508 */
3509
3510 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3511 {
3512         DSTACK(__FUNCTION_NAME);
3513         std::ostringstream os(std::ios_base::binary);
3514
3515         writeU16(os, TOCLIENT_HP);
3516         writeU8(os, hp);
3517
3518         // Make data buffer
3519         std::string s = os.str();
3520         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3521         // Send as reliable
3522         con.Send(peer_id, 0, data, true);
3523 }
3524
3525 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3526                 const std::wstring &reason)
3527 {
3528         DSTACK(__FUNCTION_NAME);
3529         std::ostringstream os(std::ios_base::binary);
3530
3531         writeU16(os, TOCLIENT_ACCESS_DENIED);
3532         os<<serializeWideString(reason);
3533
3534         // Make data buffer
3535         std::string s = os.str();
3536         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3537         // Send as reliable
3538         con.Send(peer_id, 0, data, true);
3539 }
3540
3541 /*
3542         Non-static send methods
3543 */
3544
3545 void Server::SendObjectData(float dtime)
3546 {
3547         DSTACK(__FUNCTION_NAME);
3548
3549         core::map<v3s16, bool> stepped_blocks;
3550         
3551         for(core::map<u16, RemoteClient*>::Iterator
3552                 i = m_clients.getIterator();
3553                 i.atEnd() == false; i++)
3554         {
3555                 u16 peer_id = i.getNode()->getKey();
3556                 RemoteClient *client = i.getNode()->getValue();
3557                 assert(client->peer_id == peer_id);
3558                 
3559                 if(client->serialization_version == SER_FMT_VER_INVALID)
3560                         continue;
3561                 
3562                 client->SendObjectData(this, dtime, stepped_blocks);
3563         }
3564 }
3565
3566 void Server::SendPlayerInfos()
3567 {
3568         DSTACK(__FUNCTION_NAME);
3569
3570         //JMutexAutoLock envlock(m_env_mutex);
3571         
3572         // Get connected players
3573         core::list<Player*> players = m_env.getPlayers(true);
3574         
3575         u32 player_count = players.getSize();
3576         u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3577
3578         SharedBuffer<u8> data(datasize);
3579         writeU16(&data[0], TOCLIENT_PLAYERINFO);
3580         
3581         u32 start = 2;
3582         core::list<Player*>::Iterator i;
3583         for(i = players.begin();
3584                         i != players.end(); i++)
3585         {
3586                 Player *player = *i;
3587
3588                 /*dstream<<"Server sending player info for player with "
3589                                 "peer_id="<<player->peer_id<<std::endl;*/
3590                 
3591                 writeU16(&data[start], player->peer_id);
3592                 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3593                 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3594                 start += 2+PLAYERNAME_SIZE;
3595         }
3596
3597         //JMutexAutoLock conlock(m_con_mutex);
3598
3599         // Send as reliable
3600         m_con.SendToAll(0, data, true);
3601 }
3602
3603 void Server::SendInventory(u16 peer_id)
3604 {
3605         DSTACK(__FUNCTION_NAME);
3606         
3607         Player* player = m_env.getPlayer(peer_id);
3608         assert(player);
3609
3610         /*
3611                 Serialize it
3612         */
3613
3614         std::ostringstream os;
3615         //os.imbue(std::locale("C"));
3616
3617         player->inventory.serialize(os);
3618
3619         std::string s = os.str();
3620         
3621         SharedBuffer<u8> data(s.size()+2);
3622         writeU16(&data[0], TOCLIENT_INVENTORY);
3623         memcpy(&data[2], s.c_str(), s.size());
3624         
3625         // Send as reliable
3626         m_con.Send(peer_id, 0, data, true);
3627 }
3628
3629 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3630 {
3631         DSTACK(__FUNCTION_NAME);
3632         
3633         std::ostringstream os(std::ios_base::binary);
3634         u8 buf[12];
3635         
3636         // Write command
3637         writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3638         os.write((char*)buf, 2);
3639         
3640         // Write length
3641         writeU16(buf, message.size());
3642         os.write((char*)buf, 2);
3643         
3644         // Write string
3645         for(u32 i=0; i<message.size(); i++)
3646         {
3647                 u16 w = message[i];
3648                 writeU16(buf, w);
3649                 os.write((char*)buf, 2);
3650         }
3651         
3652         // Make data buffer
3653         std::string s = os.str();
3654         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3655         // Send as reliable
3656         m_con.Send(peer_id, 0, data, true);
3657 }
3658
3659 void Server::BroadcastChatMessage(const std::wstring &message)
3660 {
3661         for(core::map<u16, RemoteClient*>::Iterator
3662                 i = m_clients.getIterator();
3663                 i.atEnd() == false; i++)
3664         {
3665                 // Get client and check that it is valid
3666                 RemoteClient *client = i.getNode()->getValue();
3667                 assert(client->peer_id == i.getNode()->getKey());
3668                 if(client->serialization_version == SER_FMT_VER_INVALID)
3669                         continue;
3670
3671                 SendChatMessage(client->peer_id, message);
3672         }
3673 }
3674
3675 void Server::SendPlayerHP(Player *player)
3676 {
3677         SendHP(m_con, player->peer_id, player->hp);
3678 }
3679
3680 void Server::SendMovePlayer(Player *player)
3681 {
3682         DSTACK(__FUNCTION_NAME);
3683         std::ostringstream os(std::ios_base::binary);
3684
3685         writeU16(os, TOCLIENT_MOVE_PLAYER);
3686         writeV3F1000(os, player->getPosition());
3687         writeF1000(os, player->getPitch());
3688         writeF1000(os, player->getYaw());
3689         
3690         {
3691                 v3f pos = player->getPosition();
3692                 f32 pitch = player->getPitch();
3693                 f32 yaw = player->getYaw();
3694                 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3695                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3696                                 <<" pitch="<<pitch
3697                                 <<" yaw="<<yaw
3698                                 <<std::endl;
3699         }
3700
3701         // Make data buffer
3702         std::string s = os.str();
3703         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3704         // Send as reliable
3705         m_con.Send(player->peer_id, 0, data, true);
3706 }
3707
3708 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3709         core::list<u16> *far_players, float far_d_nodes)
3710 {
3711         float maxd = far_d_nodes*BS;
3712         v3f p_f = intToFloat(p, BS);
3713
3714         // Create packet
3715         u32 replysize = 8;
3716         SharedBuffer<u8> reply(replysize);
3717         writeU16(&reply[0], TOCLIENT_REMOVENODE);
3718         writeS16(&reply[2], p.X);
3719         writeS16(&reply[4], p.Y);
3720         writeS16(&reply[6], p.Z);
3721
3722         for(core::map<u16, RemoteClient*>::Iterator
3723                 i = m_clients.getIterator();
3724                 i.atEnd() == false; i++)
3725         {
3726                 // Get client and check that it is valid
3727                 RemoteClient *client = i.getNode()->getValue();
3728                 assert(client->peer_id == i.getNode()->getKey());
3729                 if(client->serialization_version == SER_FMT_VER_INVALID)
3730                         continue;
3731
3732                 // Don't send if it's the same one
3733                 if(client->peer_id == ignore_id)
3734                         continue;
3735                 
3736                 if(far_players)
3737                 {
3738                         // Get player
3739                         Player *player = m_env.getPlayer(client->peer_id);
3740                         if(player)
3741                         {
3742                                 // If player is far away, only set modified blocks not sent
3743                                 v3f player_pos = player->getPosition();
3744                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3745                                 {
3746                                         far_players->push_back(client->peer_id);
3747                                         continue;
3748                                 }
3749                         }
3750                 }
3751
3752                 // Send as reliable
3753                 m_con.Send(client->peer_id, 0, reply, true);
3754         }
3755 }
3756
3757 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3758                 core::list<u16> *far_players, float far_d_nodes)
3759 {
3760         float maxd = far_d_nodes*BS;
3761         v3f p_f = intToFloat(p, BS);
3762
3763         for(core::map<u16, RemoteClient*>::Iterator
3764                 i = m_clients.getIterator();
3765                 i.atEnd() == false; i++)
3766         {
3767                 // Get client and check that it is valid
3768                 RemoteClient *client = i.getNode()->getValue();
3769                 assert(client->peer_id == i.getNode()->getKey());
3770                 if(client->serialization_version == SER_FMT_VER_INVALID)
3771                         continue;
3772
3773                 // Don't send if it's the same one
3774                 if(client->peer_id == ignore_id)
3775                         continue;
3776
3777                 if(far_players)
3778                 {
3779                         // Get player
3780                         Player *player = m_env.getPlayer(client->peer_id);
3781                         if(player)
3782                         {
3783                                 // If player is far away, only set modified blocks not sent
3784                                 v3f player_pos = player->getPosition();
3785                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3786                                 {
3787                                         far_players->push_back(client->peer_id);
3788                                         continue;
3789                                 }
3790                         }
3791                 }
3792
3793                 // Create packet
3794                 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3795                 SharedBuffer<u8> reply(replysize);
3796                 writeU16(&reply[0], TOCLIENT_ADDNODE);
3797                 writeS16(&reply[2], p.X);
3798                 writeS16(&reply[4], p.Y);
3799                 writeS16(&reply[6], p.Z);
3800                 n.serialize(&reply[8], client->serialization_version);
3801
3802                 // Send as reliable
3803                 m_con.Send(client->peer_id, 0, reply, true);
3804         }
3805 }
3806
3807 void Server::setBlockNotSent(v3s16 p)
3808 {
3809         for(core::map<u16, RemoteClient*>::Iterator
3810                 i = m_clients.getIterator();
3811                 i.atEnd()==false; i++)
3812         {
3813                 RemoteClient *client = i.getNode()->getValue();
3814                 client->SetBlockNotSent(p);
3815         }
3816 }
3817
3818 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3819 {
3820         DSTACK(__FUNCTION_NAME);
3821
3822         v3s16 p = block->getPos();
3823         
3824 #if 0
3825         // Analyze it a bit
3826         bool completely_air = true;
3827         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3828         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3829         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3830         {
3831                 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3832                 {
3833                         completely_air = false;
3834                         x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3835                 }
3836         }
3837
3838         // Print result
3839         dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3840         if(completely_air)
3841                 dstream<<"[completely air] ";
3842         dstream<<std::endl;
3843 #endif
3844
3845         /*
3846                 Create a packet with the block in the right format
3847         */
3848         
3849         std::ostringstream os(std::ios_base::binary);
3850         block->serialize(os, ver);
3851         std::string s = os.str();
3852         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3853
3854         u32 replysize = 8 + blockdata.getSize();
3855         SharedBuffer<u8> reply(replysize);
3856         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3857         writeS16(&reply[2], p.X);
3858         writeS16(&reply[4], p.Y);
3859         writeS16(&reply[6], p.Z);
3860         memcpy(&reply[8], *blockdata, blockdata.getSize());
3861
3862         /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3863                         <<":  \tpacket size: "<<replysize<<std::endl;*/
3864         
3865         /*
3866                 Send packet
3867         */
3868         m_con.Send(peer_id, 1, reply, true);
3869 }
3870
3871 void Server::SendBlocks(float dtime)
3872 {
3873         DSTACK(__FUNCTION_NAME);
3874
3875         JMutexAutoLock envlock(m_env_mutex);
3876         JMutexAutoLock conlock(m_con_mutex);
3877
3878         //TimeTaker timer("Server::SendBlocks");
3879
3880         core::array<PrioritySortedBlockTransfer> queue;
3881
3882         s32 total_sending = 0;
3883         
3884         {
3885                 ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
3886
3887                 for(core::map<u16, RemoteClient*>::Iterator
3888                         i = m_clients.getIterator();
3889                         i.atEnd() == false; i++)
3890                 {
3891                         RemoteClient *client = i.getNode()->getValue();
3892                         assert(client->peer_id == i.getNode()->getKey());
3893
3894                         total_sending += client->SendingCount();
3895                         
3896                         if(client->serialization_version == SER_FMT_VER_INVALID)
3897                                 continue;
3898                         
3899                         client->GetNextBlocks(this, dtime, queue);
3900                 }
3901         }
3902
3903         // Sort.
3904         // Lowest priority number comes first.
3905         // Lowest is most important.
3906         queue.sort();
3907
3908         for(u32 i=0; i<queue.size(); i++)
3909         {
3910                 //TODO: Calculate limit dynamically
3911                 if(total_sending >= g_settings.getS32
3912                                 ("max_simultaneous_block_sends_server_total"))
3913                         break;
3914                 
3915                 PrioritySortedBlockTransfer q = queue[i];
3916
3917                 MapBlock *block = NULL;
3918                 try
3919                 {
3920                         block = m_env.getMap().getBlockNoCreate(q.pos);
3921                 }
3922                 catch(InvalidPositionException &e)
3923                 {
3924                         continue;
3925                 }
3926
3927                 RemoteClient *client = getClient(q.peer_id);
3928
3929                 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3930
3931                 client->SentBlock(q.pos);
3932
3933                 total_sending++;
3934         }
3935 }
3936
3937 /*
3938         Something random
3939 */
3940
3941 void Server::UpdateCrafting(u16 peer_id)
3942 {
3943         DSTACK(__FUNCTION_NAME);
3944         
3945         Player* player = m_env.getPlayer(peer_id);
3946         assert(player);
3947
3948         /*
3949                 Calculate crafting stuff
3950         */
3951         if(g_settings.getBool("creative_mode") == false)
3952         {
3953                 InventoryList *clist = player->inventory.getList("craft");
3954                 InventoryList *rlist = player->inventory.getList("craftresult");
3955
3956                 if(rlist->getUsedSlots() == 0)
3957                         player->craftresult_is_preview = true;
3958
3959                 if(rlist && player->craftresult_is_preview)
3960                 {
3961                         rlist->clearItems();
3962                 }
3963                 if(clist && rlist && player->craftresult_is_preview)
3964                 {
3965                         InventoryItem *items[9];
3966                         for(u16 i=0; i<9; i++)
3967                         {
3968                                 items[i] = clist->getItem(i);
3969                         }
3970                         
3971                         // Get result of crafting grid
3972                         InventoryItem *result = craft_get_result(items);
3973                         if(result)
3974                                 rlist->addItem(result);
3975                 }
3976         
3977         } // if creative_mode == false
3978 }
3979
3980 RemoteClient* Server::getClient(u16 peer_id)
3981 {
3982         DSTACK(__FUNCTION_NAME);
3983         //JMutexAutoLock lock(m_con_mutex);
3984         core::map<u16, RemoteClient*>::Node *n;
3985         n = m_clients.find(peer_id);
3986         // A client should exist for all peers
3987         assert(n != NULL);
3988         return n->getValue();
3989 }
3990
3991 std::wstring Server::getStatusString()
3992 {
3993         std::wostringstream os(std::ios_base::binary);
3994         os<<L"# Server: ";
3995         // Version
3996         os<<L"version="<<narrow_to_wide(VERSION_STRING);
3997         // Uptime
3998         os<<L", uptime="<<m_uptime.get();
3999         // Information about clients
4000         os<<L", clients={";
4001         for(core::map<u16, RemoteClient*>::Iterator
4002                 i = m_clients.getIterator();
4003                 i.atEnd() == false; i++)
4004         {
4005                 // Get client and check that it is valid
4006                 RemoteClient *client = i.getNode()->getValue();
4007                 assert(client->peer_id == i.getNode()->getKey());
4008                 if(client->serialization_version == SER_FMT_VER_INVALID)
4009                         continue;
4010                 // Get player
4011                 Player *player = m_env.getPlayer(client->peer_id);
4012                 // Get name of player
4013                 std::wstring name = L"unknown";
4014                 if(player != NULL)
4015                         name = narrow_to_wide(player->getName());
4016                 // Add name to information string
4017                 os<<name<<L",";
4018         }
4019         os<<L"}";
4020         if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
4021                 os<<" WARNING: Map saving is disabled."<<std::endl;
4022         return os.str();
4023 }
4024
4025 v3f findSpawnPos(ServerMap &map)
4026 {
4027         //return v3f(50,50,50)*BS;
4028
4029         v2s16 nodepos;
4030         s16 groundheight = 0;
4031         
4032 #if 0
4033         nodepos = v2s16(0,0);
4034         groundheight = 20;
4035 #endif
4036
4037 #if 1
4038         // Try to find a good place a few times
4039         for(s32 i=0; i<1000; i++)
4040         {
4041                 s32 range = 1 + i;
4042                 // We're going to try to throw the player to this position
4043                 nodepos = v2s16(-range + (myrand()%(range*2)),
4044                                 -range + (myrand()%(range*2)));
4045                 v2s16 sectorpos = getNodeSectorPos(nodepos);
4046                 // Get sector (NOTE: Don't get because it's slow)
4047                 //m_env.getMap().emergeSector(sectorpos);
4048                 // Get ground height at point (fallbacks to heightmap function)
4049                 groundheight = map.findGroundLevel(nodepos);
4050                 // Don't go underwater
4051                 if(groundheight < WATER_LEVEL)
4052                 {
4053                         //dstream<<"-> Underwater"<<std::endl;
4054                         continue;
4055                 }
4056                 // Don't go to high places
4057                 if(groundheight > WATER_LEVEL + 4)
4058                 {
4059                         //dstream<<"-> Underwater"<<std::endl;
4060                         continue;
4061                 }
4062
4063                 // Found a good place
4064                 //dstream<<"Searched through "<<i<<" places."<<std::endl;
4065                 break;
4066         }
4067 #endif
4068         
4069         // If no suitable place was not found, go above water at least.
4070         if(groundheight < WATER_LEVEL)
4071                 groundheight = WATER_LEVEL;
4072
4073         return intToFloat(v3s16(
4074                         nodepos.X,
4075                         groundheight + 3,
4076                         nodepos.Y
4077                         ), BS);
4078 }
4079
4080 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4081 {
4082         /*
4083                 Try to get an existing player
4084         */
4085         Player *player = m_env.getPlayer(name);
4086         if(player != NULL)
4087         {
4088                 // If player is already connected, cancel
4089                 if(player->peer_id != 0)
4090                 {
4091                         dstream<<"emergePlayer(): Player already connected"<<std::endl;
4092                         return NULL;
4093                 }
4094
4095                 // Got one.
4096                 player->peer_id = peer_id;
4097                 
4098                 // Reset inventory to creative if in creative mode
4099                 if(g_settings.getBool("creative_mode"))
4100                 {
4101                         craft_set_creative_inventory(player);
4102                 }
4103
4104                 return player;
4105         }
4106
4107         /*
4108                 If player with the wanted peer_id already exists, cancel.
4109         */
4110         if(m_env.getPlayer(peer_id) != NULL)
4111         {
4112                 dstream<<"emergePlayer(): Player with wrong name but same"
4113                                 " peer_id already exists"<<std::endl;
4114                 return NULL;
4115         }
4116         
4117         /*
4118                 Create a new player
4119         */
4120         {
4121                 player = new ServerRemotePlayer();
4122                 //player->peer_id = c.peer_id;
4123                 //player->peer_id = PEER_ID_INEXISTENT;
4124                 player->peer_id = peer_id;
4125                 player->updateName(name);
4126                 m_authmanager.add(name);
4127                 m_authmanager.setPassword(name, password);
4128                 m_authmanager.setPrivs(name,
4129                                 stringToPrivs(g_settings.get("default_privs")));
4130
4131                 /*
4132                         Set player position
4133                 */
4134                 
4135                 dstream<<"Server: Finding spawn place for player \""
4136                                 <<player->getName()<<"\""<<std::endl;
4137
4138                 v3f pos = findSpawnPos(m_env.getServerMap());
4139
4140                 player->setPosition(pos);
4141
4142                 /*
4143                         Add player to environment
4144                 */
4145
4146                 m_env.addPlayer(player);
4147
4148                 /*
4149                         Add stuff to inventory
4150                 */
4151                 
4152                 if(g_settings.getBool("creative_mode"))
4153                 {
4154                         craft_set_creative_inventory(player);
4155                 }
4156                 else if(g_settings.getBool("give_initial_stuff"))
4157                 {
4158                         craft_give_initial_stuff(player);
4159                 }
4160
4161                 return player;
4162                 
4163         } // create new player
4164 }
4165
4166 void Server::handlePeerChange(PeerChange &c)
4167 {
4168         JMutexAutoLock envlock(m_env_mutex);
4169         JMutexAutoLock conlock(m_con_mutex);
4170         
4171         if(c.type == PEER_ADDED)
4172         {
4173                 /*
4174                         Add
4175                 */
4176
4177                 // Error check
4178                 core::map<u16, RemoteClient*>::Node *n;
4179                 n = m_clients.find(c.peer_id);
4180                 // The client shouldn't already exist
4181                 assert(n == NULL);
4182
4183                 // Create client
4184                 RemoteClient *client = new RemoteClient();
4185                 client->peer_id = c.peer_id;
4186                 m_clients.insert(client->peer_id, client);
4187
4188         } // PEER_ADDED
4189         else if(c.type == PEER_REMOVED)
4190         {
4191                 /*
4192                         Delete
4193                 */
4194
4195                 // Error check
4196                 core::map<u16, RemoteClient*>::Node *n;
4197                 n = m_clients.find(c.peer_id);
4198                 // The client should exist
4199                 assert(n != NULL);
4200                 
4201                 /*
4202                         Mark objects to be not known by the client
4203                 */
4204                 RemoteClient *client = n->getValue();
4205                 // Handle objects
4206                 for(core::map<u16, bool>::Iterator
4207                                 i = client->m_known_objects.getIterator();
4208                                 i.atEnd()==false; i++)
4209                 {
4210                         // Get object
4211                         u16 id = i.getNode()->getKey();
4212                         ServerActiveObject* obj = m_env.getActiveObject(id);
4213                         
4214                         if(obj && obj->m_known_by_count > 0)
4215                                 obj->m_known_by_count--;
4216                 }
4217
4218                 // Collect information about leaving in chat
4219                 std::wstring message;
4220                 {
4221                         std::wstring name = L"unknown";
4222                         Player *player = m_env.getPlayer(c.peer_id);
4223                         if(player != NULL)
4224                                 name = narrow_to_wide(player->getName());
4225                         
4226                         message += L"*** ";
4227                         message += name;
4228                         message += L" left game";
4229                         if(c.timeout)
4230                                 message += L" (timed out)";
4231                 }
4232
4233                 /*// Delete player
4234                 {
4235                         m_env.removePlayer(c.peer_id);
4236                 }*/
4237
4238                 // Set player client disconnected
4239                 {
4240                         Player *player = m_env.getPlayer(c.peer_id);
4241                         if(player != NULL)
4242                                 player->peer_id = 0;
4243                 }
4244                 
4245                 // Delete client
4246                 delete m_clients[c.peer_id];
4247                 m_clients.remove(c.peer_id);
4248
4249                 // Send player info to all remaining clients
4250                 SendPlayerInfos();
4251                 
4252                 // Send leave chat message to all remaining clients
4253                 BroadcastChatMessage(message);
4254                 
4255         } // PEER_REMOVED
4256         else
4257         {
4258                 assert(0);
4259         }
4260 }
4261
4262 void Server::handlePeerChanges()
4263 {
4264         while(m_peer_change_queue.size() > 0)
4265         {
4266                 PeerChange c = m_peer_change_queue.pop_front();
4267
4268                 dout_server<<"Server: Handling peer change: "
4269                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4270                                 <<std::endl;
4271
4272                 handlePeerChange(c);
4273         }
4274 }
4275
4276 u64 Server::getPlayerPrivs(Player *player)
4277 {
4278         if(player==NULL)
4279                 return 0;
4280         std::string playername = player->getName();
4281         // Local player gets all privileges regardless of
4282         // what's set on their account.
4283         if(g_settings.get("name") == playername)
4284         {
4285                 return PRIV_ALL;
4286         }
4287         else
4288         {
4289                 return getPlayerAuthPrivs(playername);
4290         }
4291 }
4292
4293 void dedicated_server_loop(Server &server, bool &kill)
4294 {
4295         DSTACK(__FUNCTION_NAME);
4296         
4297         dstream<<DTIME<<std::endl;
4298         dstream<<"========================"<<std::endl;
4299         dstream<<"Running dedicated server"<<std::endl;
4300         dstream<<"========================"<<std::endl;
4301         dstream<<std::endl;
4302
4303         IntervalLimiter m_profiler_interval;
4304
4305         for(;;)
4306         {
4307                 // This is kind of a hack but can be done like this
4308                 // because server.step() is very light
4309                 {
4310                         ScopeProfiler sp(&g_profiler, "dedicated server sleep");
4311                         sleep_ms(30);
4312                 }
4313                 server.step(0.030);
4314
4315                 if(server.getShutdownRequested() || kill)
4316                 {
4317                         dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4318                         break;
4319                 }
4320
4321                 /*
4322                         Profiler
4323                 */
4324                 float profiler_print_interval =
4325                                 g_settings.getFloat("profiler_print_interval");
4326                 if(profiler_print_interval != 0)
4327                 {
4328                         if(m_profiler_interval.step(0.030, profiler_print_interval))
4329                         {
4330                                 dstream<<"Profiler:"<<std::endl;
4331                                 g_profiler.print(dstream);
4332                                 g_profiler.clear();
4333                         }
4334                 }
4335                 
4336                 /*
4337                         Player info
4338                 */
4339                 static int counter = 0;
4340                 counter--;
4341                 if(counter <= 0)
4342                 {
4343                         counter = 10;
4344
4345                         core::list<PlayerInfo> list = server.getPlayerInfo();
4346                         core::list<PlayerInfo>::Iterator i;
4347                         static u32 sum_old = 0;
4348                         u32 sum = PIChecksum(list);
4349                         if(sum != sum_old)
4350                         {
4351                                 dstream<<DTIME<<"Player info:"<<std::endl;
4352                                 for(i=list.begin(); i!=list.end(); i++)
4353                                 {
4354                                         i->PrintLine(&dstream);
4355                                 }
4356                         }
4357                         sum_old = sum;
4358                 }
4359         }
4360 }
4361
4362