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