]> git.lizzy.rs Git - dragonfireclient.git/blob - src/server.cpp
made server to send map seed for testing
[dragonfireclient.git] / src / server.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "server.h"
21 #include "utility.h"
22 #include <iostream>
23 #include "clientserver.h"
24 #include "map.h"
25 #include "jmutexautolock.h"
26 #include "main.h"
27 #include "constants.h"
28 #include "voxel.h"
29 #include "materials.h"
30 #include "mineral.h"
31 #include "config.h"
32 #include "servercommand.h"
33 #include "filesys.h"
34
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                         
2007                         // Send as reliable
2008                         m_con.Send(peer_id, 0, reply, true);
2009                 }
2010
2011                 /*
2012                         Send complete position information
2013                 */
2014                 SendMovePlayer(player);
2015
2016                 return;
2017         }
2018
2019         if(command == TOSERVER_INIT2)
2020         {
2021                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
2022                                 <<peer->id<<std::endl;
2023
2024
2025                 getClient(peer->id)->serialization_version
2026                                 = getClient(peer->id)->pending_serialization_version;
2027
2028                 /*
2029                         Send some initialization data
2030                 */
2031                 
2032                 // Send player info to all players
2033                 SendPlayerInfos();
2034
2035                 // Send inventory to player
2036                 UpdateCrafting(peer->id);
2037                 SendInventory(peer->id);
2038
2039                 // Send HP
2040                 {
2041                         Player *player = m_env.getPlayer(peer_id);
2042                         SendPlayerHP(player);
2043                 }
2044                 
2045                 // Send time of day
2046                 {
2047                         SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2048                                         m_env.getTimeOfDay());
2049                         m_con.Send(peer->id, 0, data, true);
2050                 }
2051                 
2052                 // Send information about server to player in chat
2053                 SendChatMessage(peer_id, getStatusString());
2054                 
2055                 // Send information about joining in chat
2056                 {
2057                         std::wstring name = L"unknown";
2058                         Player *player = m_env.getPlayer(peer_id);
2059                         if(player != NULL)
2060                                 name = narrow_to_wide(player->getName());
2061                         
2062                         std::wstring message;
2063                         message += L"*** ";
2064                         message += name;
2065                         message += L" joined game";
2066                         BroadcastChatMessage(message);
2067                 }
2068
2069                 return;
2070         }
2071
2072         if(peer_ser_ver == SER_FMT_VER_INVALID)
2073         {
2074                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
2075                                 " serialization format invalid or not initialized."
2076                                 " Skipping incoming command="<<command<<std::endl;
2077                 return;
2078         }
2079         
2080         Player *player = m_env.getPlayer(peer_id);
2081
2082         if(player == NULL){
2083                 derr_server<<"Server::ProcessData(): Cancelling: "
2084                                 "No player for peer_id="<<peer_id
2085                                 <<std::endl;
2086                 return;
2087         }
2088         if(command == TOSERVER_PLAYERPOS)
2089         {
2090                 if(datasize < 2+12+12+4+4)
2091                         return;
2092         
2093                 u32 start = 0;
2094                 v3s32 ps = readV3S32(&data[start+2]);
2095                 v3s32 ss = readV3S32(&data[start+2+12]);
2096                 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2097                 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2098                 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2099                 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2100                 pitch = wrapDegrees(pitch);
2101                 yaw = wrapDegrees(yaw);
2102                 player->setPosition(position);
2103                 player->setSpeed(speed);
2104                 player->setPitch(pitch);
2105                 player->setYaw(yaw);
2106                 
2107                 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2108                                 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2109                                 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2110         }
2111         else if(command == TOSERVER_GOTBLOCKS)
2112         {
2113                 if(datasize < 2+1)
2114                         return;
2115                 
2116                 /*
2117                         [0] u16 command
2118                         [2] u8 count
2119                         [3] v3s16 pos_0
2120                         [3+6] v3s16 pos_1
2121                         ...
2122                 */
2123
2124                 u16 count = data[2];
2125                 for(u16 i=0; i<count; i++)
2126                 {
2127                         if((s16)datasize < 2+1+(i+1)*6)
2128                                 throw con::InvalidIncomingDataException
2129                                         ("GOTBLOCKS length is too short");
2130                         v3s16 p = readV3S16(&data[2+1+i*6]);
2131                         /*dstream<<"Server: GOTBLOCKS ("
2132                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2133                         RemoteClient *client = getClient(peer_id);
2134                         client->GotBlock(p);
2135                 }
2136         }
2137         else if(command == TOSERVER_DELETEDBLOCKS)
2138         {
2139                 if(datasize < 2+1)
2140                         return;
2141                 
2142                 /*
2143                         [0] u16 command
2144                         [2] u8 count
2145                         [3] v3s16 pos_0
2146                         [3+6] v3s16 pos_1
2147                         ...
2148                 */
2149
2150                 u16 count = data[2];
2151                 for(u16 i=0; i<count; i++)
2152                 {
2153                         if((s16)datasize < 2+1+(i+1)*6)
2154                                 throw con::InvalidIncomingDataException
2155                                         ("DELETEDBLOCKS length is too short");
2156                         v3s16 p = readV3S16(&data[2+1+i*6]);
2157                         /*dstream<<"Server: DELETEDBLOCKS ("
2158                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2159                         RemoteClient *client = getClient(peer_id);
2160                         client->SetBlockNotSent(p);
2161                 }
2162         }
2163         else if(command == TOSERVER_CLICK_OBJECT)
2164         {
2165                 if(datasize < 13)
2166                         return;
2167
2168                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2169                         return;
2170
2171                 /*
2172                         [0] u16 command
2173                         [2] u8 button (0=left, 1=right)
2174                         [3] v3s16 block
2175                         [9] s16 id
2176                         [11] u16 item
2177                 */
2178                 u8 button = readU8(&data[2]);
2179                 v3s16 p;
2180                 p.X = readS16(&data[3]);
2181                 p.Y = readS16(&data[5]);
2182                 p.Z = readS16(&data[7]);
2183                 s16 id = readS16(&data[9]);
2184                 //u16 item_i = readU16(&data[11]);
2185
2186                 MapBlock *block = NULL;
2187                 try
2188                 {
2189                         block = m_env.getMap().getBlockNoCreate(p);
2190                 }
2191                 catch(InvalidPositionException &e)
2192                 {
2193                         derr_server<<"CLICK_OBJECT block not found"<<std::endl;
2194                         return;
2195                 }
2196
2197                 MapBlockObject *obj = block->getObject(id);
2198
2199                 if(obj == NULL)
2200                 {
2201                         derr_server<<"CLICK_OBJECT object not found"<<std::endl;
2202                         return;
2203                 }
2204
2205                 //TODO: Check that object is reasonably close
2206                 
2207                 // Left click
2208                 if(button == 0)
2209                 {
2210                         InventoryList *ilist = player->inventory.getList("main");
2211                         if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2212                         {
2213                         
2214                                 // Skip if inventory has no free space
2215                                 if(ilist->getUsedSlots() == ilist->getSize())
2216                                 {
2217                                         dout_server<<"Player inventory has no free space"<<std::endl;
2218                                         return;
2219                                 }
2220                                 
2221                                 /*
2222                                         Create the inventory item
2223                                 */
2224                                 InventoryItem *item = NULL;
2225                                 // If it is an item-object, take the item from it
2226                                 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
2227                                 {
2228                                         item = ((ItemObject*)obj)->createInventoryItem();
2229                                 }
2230                                 // Else create an item of the object
2231                                 else
2232                                 {
2233                                         item = new MapBlockObjectItem
2234                                                         (obj->getInventoryString());
2235                                 }
2236                                 
2237                                 // Add to inventory and send inventory
2238                                 ilist->addItem(item);
2239                                 UpdateCrafting(player->peer_id);
2240                                 SendInventory(player->peer_id);
2241                         }
2242
2243                         // Remove from block
2244                         block->removeObject(id);
2245                 }
2246         }
2247         else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2248         {
2249                 if(datasize < 7)
2250                         return;
2251
2252                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2253                         return;
2254
2255                 /*
2256                         length: 7
2257                         [0] u16 command
2258                         [2] u8 button (0=left, 1=right)
2259                         [3] u16 id
2260                         [5] u16 item
2261                 */
2262                 u8 button = readU8(&data[2]);
2263                 u16 id = readS16(&data[3]);
2264                 u16 item_i = readU16(&data[11]);
2265         
2266                 ServerActiveObject *obj = m_env.getActiveObject(id);
2267
2268                 if(obj == NULL)
2269                 {
2270                         derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2271                                         <<std::endl;
2272                         return;
2273                 }
2274
2275                 //TODO: Check that object is reasonably close
2276                 
2277                 // Left click, pick object up (usually)
2278                 if(button == 0)
2279                 {
2280                         InventoryList *ilist = player->inventory.getList("main");
2281                         if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2282                         {
2283                         
2284                                 // Skip if inventory has no free space
2285                                 if(ilist->getUsedSlots() == ilist->getSize())
2286                                 {
2287                                         dout_server<<"Player inventory has no free space"<<std::endl;
2288                                         return;
2289                                 }
2290
2291                                 // Skip if object has been removed
2292                                 if(obj->m_removed)
2293                                         return;
2294                                 
2295                                 /*
2296                                         Create the inventory item
2297                                 */
2298                                 InventoryItem *item = obj->createPickedUpItem();
2299                                 
2300                                 if(item)
2301                                 {
2302                                         // Add to inventory and send inventory
2303                                         ilist->addItem(item);
2304                                         UpdateCrafting(player->peer_id);
2305                                         SendInventory(player->peer_id);
2306
2307                                         // Remove object from environment
2308                                         obj->m_removed = true;
2309                                 }
2310                                 else
2311                                 {
2312                                         /*
2313                                                 Item cannot be picked up. Punch it instead.
2314                                         */
2315
2316                                         ToolItem *titem = NULL;
2317                                         std::string toolname = "";
2318
2319                                         InventoryList *mlist = player->inventory.getList("main");
2320                                         if(mlist != NULL)
2321                                         {
2322                                                 InventoryItem *item = mlist->getItem(item_i);
2323                                                 if(item && (std::string)item->getName() == "ToolItem")
2324                                                 {
2325                                                         titem = (ToolItem*)item;
2326                                                         toolname = titem->getToolName();
2327                                                 }
2328                                         }
2329                                         
2330                                         u16 wear = obj->punch(toolname);
2331                                         
2332                                         if(titem)
2333                                         {
2334                                                 bool weared_out = titem->addWear(wear);
2335                                                 if(weared_out)
2336                                                         mlist->deleteItem(item_i);
2337                                                 SendInventory(player->peer_id);
2338                                         }
2339                                 }
2340                         }
2341                 }
2342         }
2343         else if(command == TOSERVER_GROUND_ACTION)
2344         {
2345                 if(datasize < 17)
2346                         return;
2347                 /*
2348                         length: 17
2349                         [0] u16 command
2350                         [2] u8 action
2351                         [3] v3s16 nodepos_undersurface
2352                         [9] v3s16 nodepos_abovesurface
2353                         [15] u16 item
2354                         actions:
2355                         0: start digging
2356                         1: place block
2357                         2: stop digging (all parameters ignored)
2358                         3: digging completed
2359                 */
2360                 u8 action = readU8(&data[2]);
2361                 v3s16 p_under;
2362                 p_under.X = readS16(&data[3]);
2363                 p_under.Y = readS16(&data[5]);
2364                 p_under.Z = readS16(&data[7]);
2365                 v3s16 p_over;
2366                 p_over.X = readS16(&data[9]);
2367                 p_over.Y = readS16(&data[11]);
2368                 p_over.Z = readS16(&data[13]);
2369                 u16 item_i = readU16(&data[15]);
2370
2371                 //TODO: Check that target is reasonably close
2372                 
2373                 /*
2374                         0: start digging
2375                 */
2376                 if(action == 0)
2377                 {
2378                         /*
2379                                 NOTE: This can be used in the future to check if
2380                                 somebody is cheating, by checking the timing.
2381                         */
2382                 } // action == 0
2383
2384                 /*
2385                         2: stop digging
2386                 */
2387                 else if(action == 2)
2388                 {
2389 #if 0
2390                         RemoteClient *client = getClient(peer->id);
2391                         JMutexAutoLock digmutex(client->m_dig_mutex);
2392                         client->m_dig_tool_item = -1;
2393 #endif
2394                 }
2395
2396                 /*
2397                         3: Digging completed
2398                 */
2399                 else if(action == 3)
2400                 {
2401                         // Mandatory parameter; actually used for nothing
2402                         core::map<v3s16, MapBlock*> modified_blocks;
2403
2404                         u8 material = CONTENT_IGNORE;
2405                         u8 mineral = MINERAL_NONE;
2406
2407                         bool cannot_remove_node = false;
2408
2409                         try
2410                         {
2411                                 MapNode n = m_env.getMap().getNode(p_under);
2412                                 // Get mineral
2413                                 mineral = n.getMineral();
2414                                 // Get material at position
2415                                 material = n.d;
2416                                 // If not yet cancelled
2417                                 if(cannot_remove_node == false)
2418                                 {
2419                                         // If it's not diggable, do nothing
2420                                         if(content_diggable(material) == false)
2421                                         {
2422                                                 derr_server<<"Server: Not finishing digging: "
2423                                                                 <<"Node not diggable"
2424                                                                 <<std::endl;
2425                                                 cannot_remove_node = true;
2426                                         }
2427                                 }
2428                                 // If not yet cancelled
2429                                 if(cannot_remove_node == false)
2430                                 {
2431                                         // Get node metadata
2432                                         NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2433                                         if(meta && meta->nodeRemovalDisabled() == true)
2434                                         {
2435                                                 derr_server<<"Server: Not finishing digging: "
2436                                                                 <<"Node metadata disables removal"
2437                                                                 <<std::endl;
2438                                                 cannot_remove_node = true;
2439                                         }
2440                                 }
2441                         }
2442                         catch(InvalidPositionException &e)
2443                         {
2444                                 derr_server<<"Server: Not finishing digging: Node not found."
2445                                                 <<" Adding block to emerge queue."
2446                                                 <<std::endl;
2447                                 m_emerge_queue.addBlock(peer_id,
2448                                                 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2449                                 cannot_remove_node = true;
2450                         }
2451
2452                         // Make sure the player is allowed to do it
2453                         if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2454                         {
2455                                 dstream<<"Player "<<player->getName()<<" cannot remove node"
2456                                                 <<" because privileges are "<<getPlayerPrivs(player)
2457                                                 <<std::endl;
2458                                 cannot_remove_node = true;
2459                         }
2460
2461                         /*
2462                                 If node can't be removed, set block to be re-sent to
2463                                 client and quit.
2464                         */
2465                         if(cannot_remove_node)
2466                         {
2467                                 derr_server<<"Server: Not finishing digging."<<std::endl;
2468
2469                                 // Client probably has wrong data.
2470                                 // Set block not sent, so that client will get
2471                                 // a valid one.
2472                                 dstream<<"Client "<<peer_id<<" tried to dig "
2473                                                 <<"node; but node cannot be removed."
2474                                                 <<" setting MapBlock not sent."<<std::endl;
2475                                 RemoteClient *client = getClient(peer_id);
2476                                 v3s16 blockpos = getNodeBlockPos(p_under);
2477                                 client->SetBlockNotSent(blockpos);
2478                                         
2479                                 return;
2480                         }
2481                         
2482                         /*
2483                                 Send the removal to all other clients.
2484                                 - If other player is close, send REMOVENODE
2485                                 - Otherwise set blocks not sent
2486                         */
2487                         core::list<u16> far_players;
2488                         sendRemoveNode(p_under, peer_id, &far_players, 100);
2489                         
2490                         /*
2491                                 Update and send inventory
2492                         */
2493
2494                         if(g_settings.getBool("creative_mode") == false)
2495                         {
2496                                 /*
2497                                         Wear out tool
2498                                 */
2499                                 InventoryList *mlist = player->inventory.getList("main");
2500                                 if(mlist != NULL)
2501                                 {
2502                                         InventoryItem *item = mlist->getItem(item_i);
2503                                         if(item && (std::string)item->getName() == "ToolItem")
2504                                         {
2505                                                 ToolItem *titem = (ToolItem*)item;
2506                                                 std::string toolname = titem->getToolName();
2507
2508                                                 // Get digging properties for material and tool
2509                                                 DiggingProperties prop =
2510                                                                 getDiggingProperties(material, toolname);
2511
2512                                                 if(prop.diggable == false)
2513                                                 {
2514                                                         derr_server<<"Server: WARNING: Player digged"
2515                                                                         <<" with impossible material + tool"
2516                                                                         <<" combination"<<std::endl;
2517                                                 }
2518                                                 
2519                                                 bool weared_out = titem->addWear(prop.wear);
2520
2521                                                 if(weared_out)
2522                                                 {
2523                                                         mlist->deleteItem(item_i);
2524                                                 }
2525                                         }
2526                                 }
2527
2528                                 /*
2529                                         Add dug item to inventory
2530                                 */
2531
2532                                 InventoryItem *item = NULL;
2533
2534                                 if(mineral != MINERAL_NONE)
2535                                         item = getDiggedMineralItem(mineral);
2536                                 
2537                                 // If not mineral
2538                                 if(item == NULL)
2539                                 {
2540                                         std::string &dug_s = content_features(material).dug_item;
2541                                         if(dug_s != "")
2542                                         {
2543                                                 std::istringstream is(dug_s, std::ios::binary);
2544                                                 item = InventoryItem::deSerialize(is);
2545                                         }
2546                                 }
2547                                 
2548                                 if(item != NULL)
2549                                 {
2550                                         // Add a item to inventory
2551                                         player->inventory.addItem("main", item);
2552
2553                                         // Send inventory
2554                                         UpdateCrafting(player->peer_id);
2555                                         SendInventory(player->peer_id);
2556                                 }
2557                         }
2558
2559                         /*
2560                                 Remove the node
2561                                 (this takes some time so it is done after the quick stuff)
2562                         */
2563                         m_ignore_map_edit_events = true;
2564                         m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2565                         m_ignore_map_edit_events = false;
2566                         
2567                         /*
2568                                 Set blocks not sent to far players
2569                         */
2570                         for(core::list<u16>::Iterator
2571                                         i = far_players.begin();
2572                                         i != far_players.end(); i++)
2573                         {
2574                                 u16 peer_id = *i;
2575                                 RemoteClient *client = getClient(peer_id);
2576                                 if(client==NULL)
2577                                         continue;
2578                                 client->SetBlocksNotSent(modified_blocks);
2579                         }
2580                 }
2581                 
2582                 /*
2583                         1: place block
2584                 */
2585                 else if(action == 1)
2586                 {
2587
2588                         InventoryList *ilist = player->inventory.getList("main");
2589                         if(ilist == NULL)
2590                                 return;
2591
2592                         // Get item
2593                         InventoryItem *item = ilist->getItem(item_i);
2594                         
2595                         // If there is no item, it is not possible to add it anywhere
2596                         if(item == NULL)
2597                                 return;
2598                         
2599                         /*
2600                                 Handle material items
2601                         */
2602                         if(std::string("MaterialItem") == item->getName())
2603                         {
2604                                 try{
2605                                         // Don't add a node if this is not a free space
2606                                         MapNode n2 = m_env.getMap().getNode(p_over);
2607                                         bool no_enough_privs =
2608                                                         ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2609                                         if(no_enough_privs)
2610                                                 dstream<<"Player "<<player->getName()<<" cannot add node"
2611                                                         <<" because privileges are "<<getPlayerPrivs(player)
2612                                                         <<std::endl;
2613
2614                                         if(content_buildable_to(n2.d) == false
2615                                                 || no_enough_privs)
2616                                         {
2617                                                 // Client probably has wrong data.
2618                                                 // Set block not sent, so that client will get
2619                                                 // a valid one.
2620                                                 dstream<<"Client "<<peer_id<<" tried to place"
2621                                                                 <<" node in invalid position; setting"
2622                                                                 <<" MapBlock not sent."<<std::endl;
2623                                                 RemoteClient *client = getClient(peer_id);
2624                                                 v3s16 blockpos = getNodeBlockPos(p_over);
2625                                                 client->SetBlockNotSent(blockpos);
2626                                                 return;
2627                                         }
2628                                 }
2629                                 catch(InvalidPositionException &e)
2630                                 {
2631                                         derr_server<<"Server: Ignoring ADDNODE: Node not found"
2632                                                         <<" Adding block to emerge queue."
2633                                                         <<std::endl;
2634                                         m_emerge_queue.addBlock(peer_id,
2635                                                         getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2636                                         return;
2637                                 }
2638
2639                                 // Reset build time counter
2640                                 getClient(peer->id)->m_time_from_building = 0.0;
2641                                 
2642                                 // Create node data
2643                                 MaterialItem *mitem = (MaterialItem*)item;
2644                                 MapNode n;
2645                                 n.d = mitem->getMaterial();
2646                                 if(content_features(n.d).wall_mounted)
2647                                         n.dir = packDir(p_under - p_over);
2648                                 
2649                                 /*
2650                                         Send to all players
2651                                 */
2652                                 core::list<u16> far_players;
2653                                 sendAddNode(p_over, n, 0, &far_players, 100);
2654                                 
2655                                 /*
2656                                         Handle inventory
2657                                 */
2658                                 InventoryList *ilist = player->inventory.getList("main");
2659                                 if(g_settings.getBool("creative_mode") == false && ilist)
2660                                 {
2661                                         // Remove from inventory and send inventory
2662                                         if(mitem->getCount() == 1)
2663                                                 ilist->deleteItem(item_i);
2664                                         else
2665                                                 mitem->remove(1);
2666                                         // Send inventory
2667                                         UpdateCrafting(peer_id);
2668                                         SendInventory(peer_id);
2669                                 }
2670                                 
2671                                 /*
2672                                         Add node.
2673
2674                                         This takes some time so it is done after the quick stuff
2675                                 */
2676                                 core::map<v3s16, MapBlock*> modified_blocks;
2677                                 m_ignore_map_edit_events = true;
2678                                 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2679                                 m_ignore_map_edit_events = false;
2680                                 
2681                                 /*
2682                                         Set blocks not sent to far players
2683                                 */
2684                                 for(core::list<u16>::Iterator
2685                                                 i = far_players.begin();
2686                                                 i != far_players.end(); i++)
2687                                 {
2688                                         u16 peer_id = *i;
2689                                         RemoteClient *client = getClient(peer_id);
2690                                         if(client==NULL)
2691                                                 continue;
2692                                         client->SetBlocksNotSent(modified_blocks);
2693                                 }
2694
2695                                 /*
2696                                         Calculate special events
2697                                 */
2698                                 
2699                                 /*if(n.d == CONTENT_MESE)
2700                                 {
2701                                         u32 count = 0;
2702                                         for(s16 z=-1; z<=1; z++)
2703                                         for(s16 y=-1; y<=1; y++)
2704                                         for(s16 x=-1; x<=1; x++)
2705                                         {
2706                                                 
2707                                         }
2708                                 }*/
2709                         }
2710                         /*
2711                                 Place other item (not a block)
2712                         */
2713                         else
2714                         {
2715                                 v3s16 blockpos = getNodeBlockPos(p_over);
2716                                 
2717                                 /*
2718                                         Check that the block is loaded so that the item
2719                                         can properly be added to the static list too
2720                                 */
2721                                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2722                                 if(block==NULL)
2723                                 {
2724                                         derr_server<<"Error while placing object: "
2725                                                         "block not found"<<std::endl;
2726                                         return;
2727                                 }
2728
2729                                 dout_server<<"Placing a miscellaneous item on map"
2730                                                 <<std::endl;
2731                                 
2732                                 // Calculate a position for it
2733                                 v3f pos = intToFloat(p_over, BS);
2734                                 //pos.Y -= BS*0.45;
2735                                 pos.Y -= BS*0.25; // let it drop a bit
2736                                 // Randomize a bit
2737                                 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2738                                 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2739
2740                                 /*
2741                                         Create the object
2742                                 */
2743                                 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2744
2745                                 if(obj == NULL)
2746                                 {
2747                                         derr_server<<"WARNING: item resulted in NULL object, "
2748                                                         <<"not placing onto map"
2749                                                         <<std::endl;
2750                                 }
2751                                 else
2752                                 {
2753                                         // Add the object to the environment
2754                                         m_env.addActiveObject(obj);
2755                                         
2756                                         dout_server<<"Placed object"<<std::endl;
2757
2758                                         if(g_settings.getBool("creative_mode") == false)
2759                                         {
2760                                                 // Delete the right amount of items from the slot
2761                                                 u16 dropcount = item->getDropCount();
2762                                                 
2763                                                 // Delete item if all gone
2764                                                 if(item->getCount() <= dropcount)
2765                                                 {
2766                                                         if(item->getCount() < dropcount)
2767                                                                 dstream<<"WARNING: Server: dropped more items"
2768                                                                                 <<" than the slot contains"<<std::endl;
2769                                                         
2770                                                         InventoryList *ilist = player->inventory.getList("main");
2771                                                         if(ilist)
2772                                                                 // Remove from inventory and send inventory
2773                                                                 ilist->deleteItem(item_i);
2774                                                 }
2775                                                 // Else decrement it
2776                                                 else
2777                                                         item->remove(dropcount);
2778                                                 
2779                                                 // Send inventory
2780                                                 UpdateCrafting(peer_id);
2781                                                 SendInventory(peer_id);
2782                                         }
2783                                 }
2784                         }
2785
2786                 } // action == 1
2787
2788                 /*
2789                         Catch invalid actions
2790                 */
2791                 else
2792                 {
2793                         derr_server<<"WARNING: Server: Invalid action "
2794                                         <<action<<std::endl;
2795                 }
2796         }
2797 #if 0
2798         else if(command == TOSERVER_RELEASE)
2799         {
2800                 if(datasize < 3)
2801                         return;
2802                 /*
2803                         length: 3
2804                         [0] u16 command
2805                         [2] u8 button
2806                 */
2807                 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
2808         }
2809 #endif
2810         else if(command == TOSERVER_SIGNTEXT)
2811         {
2812                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2813                         return;
2814                 /*
2815                         u16 command
2816                         v3s16 blockpos
2817                         s16 id
2818                         u16 textlen
2819                         textdata
2820                 */
2821                 std::string datastring((char*)&data[2], datasize-2);
2822                 std::istringstream is(datastring, std::ios_base::binary);
2823                 u8 buf[6];
2824                 // Read stuff
2825                 is.read((char*)buf, 6);
2826                 v3s16 blockpos = readV3S16(buf);
2827                 is.read((char*)buf, 2);
2828                 s16 id = readS16(buf);
2829                 is.read((char*)buf, 2);
2830                 u16 textlen = readU16(buf);
2831                 std::string text;
2832                 for(u16 i=0; i<textlen; i++)
2833                 {
2834                         is.read((char*)buf, 1);
2835                         text += (char)buf[0];
2836                 }
2837
2838                 MapBlock *block = NULL;
2839                 try
2840                 {
2841                         block = m_env.getMap().getBlockNoCreate(blockpos);
2842                 }
2843                 catch(InvalidPositionException &e)
2844                 {
2845                         derr_server<<"Error while setting sign text: "
2846                                         "block not found"<<std::endl;
2847                         return;
2848                 }
2849
2850                 MapBlockObject *obj = block->getObject(id);
2851                 if(obj == NULL)
2852                 {
2853                         derr_server<<"Error while setting sign text: "
2854                                         "object not found"<<std::endl;
2855                         return;
2856                 }
2857                 
2858                 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
2859                 {
2860                         derr_server<<"Error while setting sign text: "
2861                                         "object is not a sign"<<std::endl;
2862                         return;
2863                 }
2864
2865                 ((SignObject*)obj)->setText(text);
2866
2867                 obj->getBlock()->setChangedFlag();
2868         }
2869         else if(command == TOSERVER_SIGNNODETEXT)
2870         {
2871                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2872                         return;
2873                 /*
2874                         u16 command
2875                         v3s16 p
2876                         u16 textlen
2877                         textdata
2878                 */
2879                 std::string datastring((char*)&data[2], datasize-2);
2880                 std::istringstream is(datastring, std::ios_base::binary);
2881                 u8 buf[6];
2882                 // Read stuff
2883                 is.read((char*)buf, 6);
2884                 v3s16 p = readV3S16(buf);
2885                 is.read((char*)buf, 2);
2886                 u16 textlen = readU16(buf);
2887                 std::string text;
2888                 for(u16 i=0; i<textlen; i++)
2889                 {
2890                         is.read((char*)buf, 1);
2891                         text += (char)buf[0];
2892                 }
2893
2894                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
2895                 if(!meta)
2896                         return;
2897                 if(meta->typeId() != CONTENT_SIGN_WALL)
2898                         return;
2899                 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
2900                 signmeta->setText(text);
2901                 
2902                 v3s16 blockpos = getNodeBlockPos(p);
2903                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2904                 if(block)
2905                 {
2906                         block->setChangedFlag();
2907                 }
2908
2909                 for(core::map<u16, RemoteClient*>::Iterator
2910                         i = m_clients.getIterator();
2911                         i.atEnd()==false; i++)
2912                 {
2913                         RemoteClient *client = i.getNode()->getValue();
2914                         client->SetBlockNotSent(blockpos);
2915                 }
2916         }
2917         else if(command == TOSERVER_INVENTORY_ACTION)
2918         {
2919                 /*// Ignore inventory changes if in creative mode
2920                 if(g_settings.getBool("creative_mode") == true)
2921                 {
2922                         dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
2923                                         <<std::endl;
2924                         return;
2925                 }*/
2926                 // Strip command and create a stream
2927                 std::string datastring((char*)&data[2], datasize-2);
2928                 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2929                 std::istringstream is(datastring, std::ios_base::binary);
2930                 // Create an action
2931                 InventoryAction *a = InventoryAction::deSerialize(is);
2932                 if(a != NULL)
2933                 {
2934                         // Create context
2935                         InventoryContext c;
2936                         c.current_player = player;
2937
2938                         /*
2939                                 Handle craftresult specially if not in creative mode
2940                         */
2941                         bool disable_action = false;
2942                         if(a->getType() == IACTION_MOVE
2943                                         && g_settings.getBool("creative_mode") == false)
2944                         {
2945                                 IMoveAction *ma = (IMoveAction*)a;
2946                                 if(ma->to_inv == "current_player" &&
2947                                                 ma->from_inv == "current_player")
2948                                 {
2949                                         InventoryList *rlist = player->inventory.getList("craftresult");
2950                                         assert(rlist);
2951                                         InventoryList *clist = player->inventory.getList("craft");
2952                                         assert(clist);
2953                                         InventoryList *mlist = player->inventory.getList("main");
2954                                         assert(mlist);
2955                                         /*
2956                                                 Craftresult is no longer preview if something
2957                                                 is moved into it
2958                                         */
2959                                         if(ma->to_list == "craftresult"
2960                                                         && ma->from_list != "craftresult")
2961                                         {
2962                                                 // If it currently is a preview, remove
2963                                                 // its contents
2964                                                 if(player->craftresult_is_preview)
2965                                                 {
2966                                                         rlist->deleteItem(0);
2967                                                 }
2968                                                 player->craftresult_is_preview = false;
2969                                         }
2970                                         /*
2971                                                 Crafting takes place if this condition is true.
2972                                         */
2973                                         if(player->craftresult_is_preview &&
2974                                                         ma->from_list == "craftresult")
2975                                         {
2976                                                 player->craftresult_is_preview = false;
2977                                                 clist->decrementMaterials(1);
2978                                         }
2979                                         /*
2980                                                 If the craftresult is placed on itself, move it to
2981                                                 main inventory instead of doing the action
2982                                         */
2983                                         if(ma->to_list == "craftresult"
2984                                                         && ma->from_list == "craftresult")
2985                                         {
2986                                                 disable_action = true;
2987                                                 
2988                                                 InventoryItem *item1 = rlist->changeItem(0, NULL);
2989                                                 mlist->addItem(item1);
2990                                         }
2991                                 }
2992                         }
2993                         
2994                         if(disable_action == false)
2995                         {
2996                                 // Feed action to player inventory
2997                                 a->apply(&c, this);
2998                                 // Eat the action
2999                                 delete a;
3000                         }
3001                         else
3002                         {
3003                                 // Send inventory
3004                                 UpdateCrafting(player->peer_id);
3005                                 SendInventory(player->peer_id);
3006                         }
3007                 }
3008                 else
3009                 {
3010                         dstream<<"TOSERVER_INVENTORY_ACTION: "
3011                                         <<"InventoryAction::deSerialize() returned NULL"
3012                                         <<std::endl;
3013                 }
3014         }
3015         else if(command == TOSERVER_CHAT_MESSAGE)
3016         {
3017                 /*
3018                         u16 command
3019                         u16 length
3020                         wstring message
3021                 */
3022                 u8 buf[6];
3023                 std::string datastring((char*)&data[2], datasize-2);
3024                 std::istringstream is(datastring, std::ios_base::binary);
3025                 
3026                 // Read stuff
3027                 is.read((char*)buf, 2);
3028                 u16 len = readU16(buf);
3029                 
3030                 std::wstring message;
3031                 for(u16 i=0; i<len; i++)
3032                 {
3033                         is.read((char*)buf, 2);
3034                         message += (wchar_t)readU16(buf);
3035                 }
3036
3037                 // Get player name of this client
3038                 std::wstring name = narrow_to_wide(player->getName());
3039                 
3040                 // Line to send to players
3041                 std::wstring line;
3042                 // Whether to send to the player that sent the line
3043                 bool send_to_sender = false;
3044                 // Whether to send to other players
3045                 bool send_to_others = false;
3046                 
3047                 // Local player gets all privileges regardless of
3048                 // what's set on their account.
3049                 u64 privs = getPlayerPrivs(player);
3050
3051                 // Parse commands
3052                 std::wstring commandprefix = L"/#";
3053                 if(message.substr(0, commandprefix.size()) == commandprefix)
3054                 {
3055                         line += L"Server: ";
3056
3057                         message = message.substr(commandprefix.size());
3058
3059                         ServerCommandContext *ctx = new ServerCommandContext(
3060                                 str_split(message, L' '),
3061                                 this,
3062                                 &m_env,
3063                                 player,
3064                                 privs);
3065
3066                         line += processServerCommand(ctx);
3067                         send_to_sender = ctx->flags & 1;
3068                         send_to_others = ctx->flags & 2;
3069                         delete ctx;
3070
3071                 }
3072                 else
3073                 {
3074                         if(privs & PRIV_SHOUT)
3075                         {
3076                                 line += L"<";
3077                                 line += name;
3078                                 line += L"> ";
3079                                 line += message;
3080                                 send_to_others = true;
3081                         }
3082                         else
3083                         {
3084                                 line += L"Server: You are not allowed to shout";
3085                                 send_to_sender = true;
3086                         }
3087                 }
3088                 
3089                 if(line != L"")
3090                 {
3091                         dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3092
3093                         /*
3094                                 Send the message to clients
3095                         */
3096                         for(core::map<u16, RemoteClient*>::Iterator
3097                                 i = m_clients.getIterator();
3098                                 i.atEnd() == false; i++)
3099                         {
3100                                 // Get client and check that it is valid
3101                                 RemoteClient *client = i.getNode()->getValue();
3102                                 assert(client->peer_id == i.getNode()->getKey());
3103                                 if(client->serialization_version == SER_FMT_VER_INVALID)
3104                                         continue;
3105
3106                                 // Filter recipient
3107                                 bool sender_selected = (peer_id == client->peer_id);
3108                                 if(sender_selected == true && send_to_sender == false)
3109                                         continue;
3110                                 if(sender_selected == false && send_to_others == false)
3111                                         continue;
3112
3113                                 SendChatMessage(client->peer_id, line);
3114                         }
3115                 }
3116         }
3117         else if(command == TOSERVER_DAMAGE)
3118         {
3119                 if(g_settings.getBool("enable_damage"))
3120                 {
3121                         std::string datastring((char*)&data[2], datasize-2);
3122                         std::istringstream is(datastring, std::ios_base::binary);
3123                         u8 damage = readU8(is);
3124                         if(player->hp > damage)
3125                         {
3126                                 player->hp -= damage;
3127                         }
3128                         else
3129                         {
3130                                 player->hp = 0;
3131
3132                                 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3133                                                 <<std::endl;
3134                                 
3135                                 v3f pos = findSpawnPos(m_env.getServerMap());
3136                                 player->setPosition(pos);
3137                                 player->hp = 20;
3138                                 SendMovePlayer(player);
3139                                 SendPlayerHP(player);
3140                                 
3141                                 //TODO: Throw items around
3142                         }
3143                 }
3144
3145                 SendPlayerHP(player);
3146         }
3147         else if(command == TOSERVER_PASSWORD)
3148         {
3149                 /*
3150                         [0] u16 TOSERVER_PASSWORD
3151                         [2] u8[28] old password
3152                         [30] u8[28] new password
3153                 */
3154
3155                 if(datasize != 2+PASSWORD_SIZE*2)
3156                         return;
3157                 /*char password[PASSWORD_SIZE];
3158                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3159                         password[i] = data[2+i];
3160                 password[PASSWORD_SIZE-1] = 0;*/
3161                 std::string oldpwd;
3162                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3163                 {
3164                         char c = data[2+i];
3165                         if(c == 0)
3166                                 break;
3167                         oldpwd += c;
3168                 }
3169                 std::string newpwd;
3170                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3171                 {
3172                         char c = data[2+PASSWORD_SIZE+i];
3173                         if(c == 0)
3174                                 break;
3175                         newpwd += c;
3176                 }
3177
3178                 std::string playername = player->getName();
3179
3180                 if(m_authmanager.exists(playername) == false)
3181                 {
3182                         dstream<<"Server: playername not found in authmanager"<<std::endl;
3183                         // Wrong old password supplied!!
3184                         SendChatMessage(peer_id, L"playername not found in authmanager");
3185                         return;
3186                 }
3187
3188                 std::string checkpwd = m_authmanager.getPassword(playername);
3189                 
3190                 if(oldpwd != checkpwd)
3191                 {
3192                         dstream<<"Server: invalid old password"<<std::endl;
3193                         // Wrong old password supplied!!
3194                         SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3195                         return;
3196                 }
3197
3198                 m_authmanager.setPassword(playername, newpwd);
3199                 
3200                 dstream<<"Server: password change successful for "<<playername
3201                                 <<std::endl;
3202                 SendChatMessage(peer_id, L"Password change successful");
3203         }
3204         else
3205         {
3206                 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3207                                 "unknown command "<<command<<std::endl;
3208         }
3209         
3210         } //try
3211         catch(SendFailedException &e)
3212         {
3213                 derr_server<<"Server::ProcessData(): SendFailedException: "
3214                                 <<"what="<<e.what()
3215                                 <<std::endl;
3216         }
3217 }
3218
3219 void Server::onMapEditEvent(MapEditEvent *event)
3220 {
3221         dstream<<"Server::onMapEditEvent()"<<std::endl;
3222         if(m_ignore_map_edit_events)
3223                 return;
3224         MapEditEvent *e = event->clone();
3225         m_unsent_map_edit_queue.push_back(e);
3226 }
3227
3228 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3229 {
3230         if(id == "current_player")
3231         {
3232                 assert(c->current_player);
3233                 return &(c->current_player->inventory);
3234         }
3235         
3236         Strfnd fn(id);
3237         std::string id0 = fn.next(":");
3238
3239         if(id0 == "nodemeta")
3240         {
3241                 v3s16 p;
3242                 p.X = stoi(fn.next(","));
3243                 p.Y = stoi(fn.next(","));
3244                 p.Z = stoi(fn.next(","));
3245                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3246                 if(meta)
3247                         return meta->getInventory();
3248                 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3249                                 <<"no metadata found"<<std::endl;
3250                 return NULL;
3251         }
3252
3253         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3254         return NULL;
3255 }
3256 void Server::inventoryModified(InventoryContext *c, std::string id)
3257 {
3258         if(id == "current_player")
3259         {
3260                 assert(c->current_player);
3261                 // Send inventory
3262                 UpdateCrafting(c->current_player->peer_id);
3263                 SendInventory(c->current_player->peer_id);
3264                 return;
3265         }
3266         
3267         Strfnd fn(id);
3268         std::string id0 = fn.next(":");
3269
3270         if(id0 == "nodemeta")
3271         {
3272                 v3s16 p;
3273                 p.X = stoi(fn.next(","));
3274                 p.Y = stoi(fn.next(","));
3275                 p.Z = stoi(fn.next(","));
3276                 v3s16 blockpos = getNodeBlockPos(p);
3277
3278                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3279                 if(meta)
3280                         meta->inventoryModified();
3281
3282                 for(core::map<u16, RemoteClient*>::Iterator
3283                         i = m_clients.getIterator();
3284                         i.atEnd()==false; i++)
3285                 {
3286                         RemoteClient *client = i.getNode()->getValue();
3287                         client->SetBlockNotSent(blockpos);
3288                 }
3289
3290                 return;
3291         }
3292
3293         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3294 }
3295
3296 core::list<PlayerInfo> Server::getPlayerInfo()
3297 {
3298         DSTACK(__FUNCTION_NAME);
3299         JMutexAutoLock envlock(m_env_mutex);
3300         JMutexAutoLock conlock(m_con_mutex);
3301         
3302         core::list<PlayerInfo> list;
3303
3304         core::list<Player*> players = m_env.getPlayers();
3305         
3306         core::list<Player*>::Iterator i;
3307         for(i = players.begin();
3308                         i != players.end(); i++)
3309         {
3310                 PlayerInfo info;
3311
3312                 Player *player = *i;
3313
3314                 try{
3315                         con::Peer *peer = m_con.GetPeer(player->peer_id);
3316                         // Copy info from peer to info struct
3317                         info.id = peer->id;
3318                         info.address = peer->address;
3319                         info.avg_rtt = peer->avg_rtt;
3320                 }
3321                 catch(con::PeerNotFoundException &e)
3322                 {
3323                         // Set dummy peer info
3324                         info.id = 0;
3325                         info.address = Address(0,0,0,0,0);
3326                         info.avg_rtt = 0.0;
3327                 }
3328
3329                 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3330                 info.position = player->getPosition();
3331
3332                 list.push_back(info);
3333         }
3334
3335         return list;
3336 }
3337
3338
3339 void Server::peerAdded(con::Peer *peer)
3340 {
3341         DSTACK(__FUNCTION_NAME);
3342         dout_server<<"Server::peerAdded(): peer->id="
3343                         <<peer->id<<std::endl;
3344         
3345         PeerChange c;
3346         c.type = PEER_ADDED;
3347         c.peer_id = peer->id;
3348         c.timeout = false;
3349         m_peer_change_queue.push_back(c);
3350 }
3351
3352 void Server::deletingPeer(con::Peer *peer, bool timeout)
3353 {
3354         DSTACK(__FUNCTION_NAME);
3355         dout_server<<"Server::deletingPeer(): peer->id="
3356                         <<peer->id<<", timeout="<<timeout<<std::endl;
3357         
3358         PeerChange c;
3359         c.type = PEER_REMOVED;
3360         c.peer_id = peer->id;
3361         c.timeout = timeout;
3362         m_peer_change_queue.push_back(c);
3363 }
3364
3365 /*
3366         Static send methods
3367 */
3368
3369 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3370 {
3371         DSTACK(__FUNCTION_NAME);
3372         std::ostringstream os(std::ios_base::binary);
3373
3374         writeU16(os, TOCLIENT_HP);
3375         writeU8(os, hp);
3376
3377         // Make data buffer
3378         std::string s = os.str();
3379         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3380         // Send as reliable
3381         con.Send(peer_id, 0, data, true);
3382 }
3383
3384 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3385                 const std::wstring &reason)
3386 {
3387         DSTACK(__FUNCTION_NAME);
3388         std::ostringstream os(std::ios_base::binary);
3389
3390         writeU16(os, TOCLIENT_ACCESS_DENIED);
3391         os<<serializeWideString(reason);
3392
3393         // Make data buffer
3394         std::string s = os.str();
3395         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3396         // Send as reliable
3397         con.Send(peer_id, 0, data, true);
3398 }
3399
3400 /*
3401         Non-static send methods
3402 */
3403
3404 void Server::SendObjectData(float dtime)
3405 {
3406         DSTACK(__FUNCTION_NAME);
3407
3408         core::map<v3s16, bool> stepped_blocks;
3409         
3410         for(core::map<u16, RemoteClient*>::Iterator
3411                 i = m_clients.getIterator();
3412                 i.atEnd() == false; i++)
3413         {
3414                 u16 peer_id = i.getNode()->getKey();
3415                 RemoteClient *client = i.getNode()->getValue();
3416                 assert(client->peer_id == peer_id);
3417                 
3418                 if(client->serialization_version == SER_FMT_VER_INVALID)
3419                         continue;
3420                 
3421                 client->SendObjectData(this, dtime, stepped_blocks);
3422         }
3423 }
3424
3425 void Server::SendPlayerInfos()
3426 {
3427         DSTACK(__FUNCTION_NAME);
3428
3429         //JMutexAutoLock envlock(m_env_mutex);
3430         
3431         // Get connected players
3432         core::list<Player*> players = m_env.getPlayers(true);
3433         
3434         u32 player_count = players.getSize();
3435         u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3436
3437         SharedBuffer<u8> data(datasize);
3438         writeU16(&data[0], TOCLIENT_PLAYERINFO);
3439         
3440         u32 start = 2;
3441         core::list<Player*>::Iterator i;
3442         for(i = players.begin();
3443                         i != players.end(); i++)
3444         {
3445                 Player *player = *i;
3446
3447                 /*dstream<<"Server sending player info for player with "
3448                                 "peer_id="<<player->peer_id<<std::endl;*/
3449                 
3450                 writeU16(&data[start], player->peer_id);
3451                 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3452                 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3453                 start += 2+PLAYERNAME_SIZE;
3454         }
3455
3456         //JMutexAutoLock conlock(m_con_mutex);
3457
3458         // Send as reliable
3459         m_con.SendToAll(0, data, true);
3460 }
3461
3462 void Server::SendInventory(u16 peer_id)
3463 {
3464         DSTACK(__FUNCTION_NAME);
3465         
3466         Player* player = m_env.getPlayer(peer_id);
3467         assert(player);
3468
3469         /*
3470                 Serialize it
3471         */
3472
3473         std::ostringstream os;
3474         //os.imbue(std::locale("C"));
3475
3476         player->inventory.serialize(os);
3477
3478         std::string s = os.str();
3479         
3480         SharedBuffer<u8> data(s.size()+2);
3481         writeU16(&data[0], TOCLIENT_INVENTORY);
3482         memcpy(&data[2], s.c_str(), s.size());
3483         
3484         // Send as reliable
3485         m_con.Send(peer_id, 0, data, true);
3486 }
3487
3488 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3489 {
3490         DSTACK(__FUNCTION_NAME);
3491         
3492         std::ostringstream os(std::ios_base::binary);
3493         u8 buf[12];
3494         
3495         // Write command
3496         writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3497         os.write((char*)buf, 2);
3498         
3499         // Write length
3500         writeU16(buf, message.size());
3501         os.write((char*)buf, 2);
3502         
3503         // Write string
3504         for(u32 i=0; i<message.size(); i++)
3505         {
3506                 u16 w = message[i];
3507                 writeU16(buf, w);
3508                 os.write((char*)buf, 2);
3509         }
3510         
3511         // Make data buffer
3512         std::string s = os.str();
3513         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3514         // Send as reliable
3515         m_con.Send(peer_id, 0, data, true);
3516 }
3517
3518 void Server::BroadcastChatMessage(const std::wstring &message)
3519 {
3520         for(core::map<u16, RemoteClient*>::Iterator
3521                 i = m_clients.getIterator();
3522                 i.atEnd() == false; i++)
3523         {
3524                 // Get client and check that it is valid
3525                 RemoteClient *client = i.getNode()->getValue();
3526                 assert(client->peer_id == i.getNode()->getKey());
3527                 if(client->serialization_version == SER_FMT_VER_INVALID)
3528                         continue;
3529
3530                 SendChatMessage(client->peer_id, message);
3531         }
3532 }
3533
3534 void Server::SendPlayerHP(Player *player)
3535 {
3536         SendHP(m_con, player->peer_id, player->hp);
3537 }
3538
3539 void Server::SendMovePlayer(Player *player)
3540 {
3541         DSTACK(__FUNCTION_NAME);
3542         std::ostringstream os(std::ios_base::binary);
3543
3544         writeU16(os, TOCLIENT_MOVE_PLAYER);
3545         writeV3F1000(os, player->getPosition());
3546         writeF1000(os, player->getPitch());
3547         writeF1000(os, player->getYaw());
3548         
3549         {
3550                 v3f pos = player->getPosition();
3551                 f32 pitch = player->getPitch();
3552                 f32 yaw = player->getYaw();
3553                 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3554                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3555                                 <<" pitch="<<pitch
3556                                 <<" yaw="<<yaw
3557                                 <<std::endl;
3558         }
3559
3560         // Make data buffer
3561         std::string s = os.str();
3562         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3563         // Send as reliable
3564         m_con.Send(player->peer_id, 0, data, true);
3565 }
3566
3567 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3568         core::list<u16> *far_players, float far_d_nodes)
3569 {
3570         float maxd = far_d_nodes*BS;
3571         v3f p_f = intToFloat(p, BS);
3572
3573         // Create packet
3574         u32 replysize = 8;
3575         SharedBuffer<u8> reply(replysize);
3576         writeU16(&reply[0], TOCLIENT_REMOVENODE);
3577         writeS16(&reply[2], p.X);
3578         writeS16(&reply[4], p.Y);
3579         writeS16(&reply[6], p.Z);
3580
3581         for(core::map<u16, RemoteClient*>::Iterator
3582                 i = m_clients.getIterator();
3583                 i.atEnd() == false; i++)
3584         {
3585                 // Get client and check that it is valid
3586                 RemoteClient *client = i.getNode()->getValue();
3587                 assert(client->peer_id == i.getNode()->getKey());
3588                 if(client->serialization_version == SER_FMT_VER_INVALID)
3589                         continue;
3590
3591                 // Don't send if it's the same one
3592                 if(client->peer_id == ignore_id)
3593                         continue;
3594                 
3595                 if(far_players)
3596                 {
3597                         // Get player
3598                         Player *player = m_env.getPlayer(client->peer_id);
3599                         if(player)
3600                         {
3601                                 // If player is far away, only set modified blocks not sent
3602                                 v3f player_pos = player->getPosition();
3603                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3604                                 {
3605                                         far_players->push_back(client->peer_id);
3606                                         continue;
3607                                 }
3608                         }
3609                 }
3610
3611                 // Send as reliable
3612                 m_con.Send(client->peer_id, 0, reply, true);
3613         }
3614 }
3615
3616 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3617                 core::list<u16> *far_players, float far_d_nodes)
3618 {
3619         float maxd = far_d_nodes*BS;
3620         v3f p_f = intToFloat(p, BS);
3621
3622         for(core::map<u16, RemoteClient*>::Iterator
3623                 i = m_clients.getIterator();
3624                 i.atEnd() == false; i++)
3625         {
3626                 // Get client and check that it is valid
3627                 RemoteClient *client = i.getNode()->getValue();
3628                 assert(client->peer_id == i.getNode()->getKey());
3629                 if(client->serialization_version == SER_FMT_VER_INVALID)
3630                         continue;
3631
3632                 // Don't send if it's the same one
3633                 if(client->peer_id == ignore_id)
3634                         continue;
3635
3636                 if(far_players)
3637                 {
3638                         // Get player
3639                         Player *player = m_env.getPlayer(client->peer_id);
3640                         if(player)
3641                         {
3642                                 // If player is far away, only set modified blocks not sent
3643                                 v3f player_pos = player->getPosition();
3644                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3645                                 {
3646                                         far_players->push_back(client->peer_id);
3647                                         continue;
3648                                 }
3649                         }
3650                 }
3651
3652                 // Create packet
3653                 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3654                 SharedBuffer<u8> reply(replysize);
3655                 writeU16(&reply[0], TOCLIENT_ADDNODE);
3656                 writeS16(&reply[2], p.X);
3657                 writeS16(&reply[4], p.Y);
3658                 writeS16(&reply[6], p.Z);
3659                 n.serialize(&reply[8], client->serialization_version);
3660
3661                 // Send as reliable
3662                 m_con.Send(client->peer_id, 0, reply, true);
3663         }
3664 }
3665
3666 void Server::setBlockNotSent(v3s16 p)
3667 {
3668         for(core::map<u16, RemoteClient*>::Iterator
3669                 i = m_clients.getIterator();
3670                 i.atEnd()==false; i++)
3671         {
3672                 RemoteClient *client = i.getNode()->getValue();
3673                 client->SetBlockNotSent(p);
3674         }
3675 }
3676
3677 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3678 {
3679         DSTACK(__FUNCTION_NAME);
3680
3681         v3s16 p = block->getPos();
3682         
3683 #if 0
3684         // Analyze it a bit
3685         bool completely_air = true;
3686         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3687         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3688         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3689         {
3690                 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3691                 {
3692                         completely_air = false;
3693                         x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3694                 }
3695         }
3696
3697         // Print result
3698         dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3699         if(completely_air)
3700                 dstream<<"[completely air] ";
3701         dstream<<std::endl;
3702 #endif
3703
3704         /*
3705                 Create a packet with the block in the right format
3706         */
3707         
3708         std::ostringstream os(std::ios_base::binary);
3709         block->serialize(os, ver);
3710         std::string s = os.str();
3711         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3712
3713         u32 replysize = 8 + blockdata.getSize();
3714         SharedBuffer<u8> reply(replysize);
3715         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3716         writeS16(&reply[2], p.X);
3717         writeS16(&reply[4], p.Y);
3718         writeS16(&reply[6], p.Z);
3719         memcpy(&reply[8], *blockdata, blockdata.getSize());
3720
3721         /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3722                         <<":  \tpacket size: "<<replysize<<std::endl;*/
3723         
3724         /*
3725                 Send packet
3726         */
3727         m_con.Send(peer_id, 1, reply, true);
3728 }
3729
3730 void Server::SendBlocks(float dtime)
3731 {
3732         DSTACK(__FUNCTION_NAME);
3733
3734         JMutexAutoLock envlock(m_env_mutex);
3735         JMutexAutoLock conlock(m_con_mutex);
3736
3737         //TimeTaker timer("Server::SendBlocks");
3738
3739         core::array<PrioritySortedBlockTransfer> queue;
3740
3741         s32 total_sending = 0;
3742         
3743         {
3744                 ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
3745
3746                 for(core::map<u16, RemoteClient*>::Iterator
3747                         i = m_clients.getIterator();
3748                         i.atEnd() == false; i++)
3749                 {
3750                         RemoteClient *client = i.getNode()->getValue();
3751                         assert(client->peer_id == i.getNode()->getKey());
3752
3753                         total_sending += client->SendingCount();
3754                         
3755                         if(client->serialization_version == SER_FMT_VER_INVALID)
3756                                 continue;
3757                         
3758                         client->GetNextBlocks(this, dtime, queue);
3759                 }
3760         }
3761
3762         // Sort.
3763         // Lowest priority number comes first.
3764         // Lowest is most important.
3765         queue.sort();
3766
3767         for(u32 i=0; i<queue.size(); i++)
3768         {
3769                 //TODO: Calculate limit dynamically
3770                 if(total_sending >= g_settings.getS32
3771                                 ("max_simultaneous_block_sends_server_total"))
3772                         break;
3773                 
3774                 PrioritySortedBlockTransfer q = queue[i];
3775
3776                 MapBlock *block = NULL;
3777                 try
3778                 {
3779                         block = m_env.getMap().getBlockNoCreate(q.pos);
3780                 }
3781                 catch(InvalidPositionException &e)
3782                 {
3783                         continue;
3784                 }
3785
3786                 RemoteClient *client = getClient(q.peer_id);
3787
3788                 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3789
3790                 client->SentBlock(q.pos);
3791
3792                 total_sending++;
3793         }
3794 }
3795
3796 /*
3797         Something random
3798 */
3799
3800 void Server::UpdateCrafting(u16 peer_id)
3801 {
3802         DSTACK(__FUNCTION_NAME);
3803         
3804         Player* player = m_env.getPlayer(peer_id);
3805         assert(player);
3806
3807         /*
3808                 Calculate crafting stuff
3809         */
3810         if(g_settings.getBool("creative_mode") == false)
3811         {
3812                 InventoryList *clist = player->inventory.getList("craft");
3813                 InventoryList *rlist = player->inventory.getList("craftresult");
3814
3815                 if(rlist->getUsedSlots() == 0)
3816                         player->craftresult_is_preview = true;
3817
3818                 if(rlist && player->craftresult_is_preview)
3819                 {
3820                         rlist->clearItems();
3821                 }
3822                 if(clist && rlist && player->craftresult_is_preview)
3823                 {
3824                         InventoryItem *items[9];
3825                         for(u16 i=0; i<9; i++)
3826                         {
3827                                 items[i] = clist->getItem(i);
3828                         }
3829                         
3830                         bool found = false;
3831
3832                         // Wood
3833                         if(!found)
3834                         {
3835                                 ItemSpec specs[9];
3836                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_TREE);
3837                                 if(checkItemCombination(items, specs))
3838                                 {
3839                                         rlist->addItem(new MaterialItem(CONTENT_WOOD, 4));
3840                                         found = true;
3841                                 }
3842                         }
3843
3844                         // Stick
3845                         if(!found)
3846                         {
3847                                 ItemSpec specs[9];
3848                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3849                                 if(checkItemCombination(items, specs))
3850                                 {
3851                                         rlist->addItem(new CraftItem("Stick", 4));
3852                                         found = true;
3853                                 }
3854                         }
3855
3856                         // Fence
3857                         if(!found)
3858                         {
3859                                 ItemSpec specs[9];
3860                                 specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
3861                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3862                                 specs[5] = ItemSpec(ITEM_CRAFT, "Stick");
3863                                 specs[6] = ItemSpec(ITEM_CRAFT, "Stick");
3864                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3865                                 specs[8] = ItemSpec(ITEM_CRAFT, "Stick");
3866                                 if(checkItemCombination(items, specs))
3867                                 {
3868                                         rlist->addItem(new MaterialItem(CONTENT_FENCE, 2));
3869                                         found = true;
3870                                 }
3871                         }
3872
3873                         // Sign
3874                         if(!found)
3875                         {
3876                                 ItemSpec specs[9];
3877                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3878                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3879                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3880                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3881                                 specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3882                                 specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3883                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3884                                 if(checkItemCombination(items, specs))
3885                                 {
3886                                         //rlist->addItem(new MapBlockObjectItem("Sign"));
3887                                         rlist->addItem(new MaterialItem(CONTENT_SIGN_WALL, 1));
3888                                         found = true;
3889                                 }
3890                         }
3891
3892                         // Torch
3893                         if(!found)
3894                         {
3895                                 ItemSpec specs[9];
3896                                 specs[0] = ItemSpec(ITEM_CRAFT, "lump_of_coal");
3897                                 specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
3898                                 if(checkItemCombination(items, specs))
3899                                 {
3900                                         rlist->addItem(new MaterialItem(CONTENT_TORCH, 4));
3901                                         found = true;
3902                                 }
3903                         }
3904
3905                         // Wooden pick
3906                         if(!found)
3907                         {
3908                                 ItemSpec specs[9];
3909                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3910                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3911                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3912                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3913                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3914                                 if(checkItemCombination(items, specs))
3915                                 {
3916                                         rlist->addItem(new ToolItem("WPick", 0));
3917                                         found = true;
3918                                 }
3919                         }
3920
3921                         // Stone pick
3922                         if(!found)
3923                         {
3924                                 ItemSpec specs[9];
3925                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3926                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3927                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3928                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3929                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3930                                 if(checkItemCombination(items, specs))
3931                                 {
3932                                         rlist->addItem(new ToolItem("STPick", 0));
3933                                         found = true;
3934                                 }
3935                         }
3936
3937                         // Steel pick
3938                         if(!found)
3939                         {
3940                                 ItemSpec specs[9];
3941                                 specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3942                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3943                                 specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3944                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3945                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3946                                 if(checkItemCombination(items, specs))
3947                                 {
3948                                         rlist->addItem(new ToolItem("SteelPick", 0));
3949                                         found = true;
3950                                 }
3951                         }
3952
3953                         // Mese pick
3954                         if(!found)
3955                         {
3956                                 ItemSpec specs[9];
3957                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
3958                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
3959                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
3960                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3961                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3962                                 if(checkItemCombination(items, specs))
3963                                 {
3964                                         rlist->addItem(new ToolItem("MesePick", 0));
3965                                         found = true;
3966                                 }
3967                         }
3968
3969                         // Wooden shovel
3970                         if(!found)
3971                         {
3972                                 ItemSpec specs[9];
3973                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3974                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3975                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3976                                 if(checkItemCombination(items, specs))
3977                                 {
3978                                         rlist->addItem(new ToolItem("WShovel", 0));
3979                                         found = true;
3980                                 }
3981                         }
3982
3983                         // Stone shovel
3984                         if(!found)
3985                         {
3986                                 ItemSpec specs[9];
3987                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3988                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3989                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3990                                 if(checkItemCombination(items, specs))
3991                                 {
3992                                         rlist->addItem(new ToolItem("STShovel", 0));
3993                                         found = true;
3994                                 }
3995                         }
3996
3997                         // Steel shovel
3998                         if(!found)
3999                         {
4000                                 ItemSpec specs[9];
4001                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
4002                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
4003                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
4004                                 if(checkItemCombination(items, specs))
4005                                 {
4006                                         rlist->addItem(new ToolItem("SteelShovel", 0));
4007                                         found = true;
4008                                 }
4009                         }
4010
4011                         // Wooden axe
4012                         if(!found)
4013                         {
4014                                 ItemSpec specs[9];
4015                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
4016                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
4017                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
4018                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
4019                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
4020                                 if(checkItemCombination(items, specs))
4021                                 {
4022                                         rlist->addItem(new ToolItem("WAxe", 0));
4023                                         found = true;
4024                                 }
4025                         }
4026
4027                         // Stone axe
4028                         if(!found)
4029                         {
4030                                 ItemSpec specs[9];
4031                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
4032                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
4033                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
4034                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
4035                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
4036                                 if(checkItemCombination(items, specs))
4037                                 {
4038                                         rlist->addItem(new ToolItem("STAxe", 0));
4039                                         found = true;
4040                                 }
4041                         }
4042
4043                         // Steel axe
4044                         if(!found)
4045                         {
4046                                 ItemSpec specs[9];
4047                                 specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
4048                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
4049                                 specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot");
4050                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
4051                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
4052                                 if(checkItemCombination(items, specs))
4053                                 {
4054                                         rlist->addItem(new ToolItem("SteelAxe", 0));
4055                                         found = true;
4056                                 }
4057                         }
4058
4059                         // Wooden sword
4060                         if(!found)
4061                         {
4062                                 ItemSpec specs[9];
4063                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
4064                                 specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
4065                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
4066                                 if(checkItemCombination(items, specs))
4067                                 {
4068                                         rlist->addItem(new ToolItem("WSword", 0));
4069                                         found = true;
4070                                 }
4071                         }
4072
4073                         // Stone sword
4074                         if(!found)
4075                         {
4076                                 ItemSpec specs[9];
4077                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
4078                                 specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
4079                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
4080                                 if(checkItemCombination(items, specs))
4081                                 {
4082                                         rlist->addItem(new ToolItem("STSword", 0));
4083                                         found = true;
4084                                 }
4085                         }
4086
4087                         // Steel sword
4088                         if(!found)
4089                         {
4090                                 ItemSpec specs[9];
4091                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
4092                                 specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot");
4093                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
4094                                 if(checkItemCombination(items, specs))
4095                                 {
4096                                         rlist->addItem(new ToolItem("SteelSword", 0));
4097                                         found = true;
4098                                 }
4099                         }
4100
4101                         // Chest
4102                         if(!found)
4103                         {
4104                                 ItemSpec specs[9];
4105                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
4106                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
4107                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
4108                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
4109                                 specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
4110                                 specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
4111                                 specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
4112                                 specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
4113                                 if(checkItemCombination(items, specs))
4114                                 {
4115                                         rlist->addItem(new MaterialItem(CONTENT_CHEST, 1));
4116                                         found = true;
4117                                 }
4118                         }
4119
4120                         // Furnace
4121                         if(!found)
4122                         {
4123                                 ItemSpec specs[9];
4124                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
4125                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
4126                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
4127                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
4128                                 specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
4129                                 specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
4130                                 specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
4131                                 specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
4132                                 if(checkItemCombination(items, specs))
4133                                 {
4134                                         rlist->addItem(new MaterialItem(CONTENT_FURNACE, 1));
4135                                         found = true;
4136                                 }
4137                         }
4138
4139                         // Steel block
4140                         if(!found)
4141                         {
4142                                 ItemSpec specs[9];
4143                                 specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
4144                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
4145                                 specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot");
4146                                 specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot");
4147                                 specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot");
4148                                 specs[5] = ItemSpec(ITEM_CRAFT, "steel_ingot");
4149                                 specs[6] = ItemSpec(ITEM_CRAFT, "steel_ingot");
4150                                 specs[7] = ItemSpec(ITEM_CRAFT, "steel_ingot");
4151                                 specs[8] = ItemSpec(ITEM_CRAFT, "steel_ingot");
4152                                 if(checkItemCombination(items, specs))
4153                                 {
4154                                         rlist->addItem(new MaterialItem(CONTENT_STEEL, 1));
4155                                         found = true;
4156                                 }
4157                         }
4158                 }
4159         
4160         } // if creative_mode == false
4161 }
4162
4163 RemoteClient* Server::getClient(u16 peer_id)
4164 {
4165         DSTACK(__FUNCTION_NAME);
4166         //JMutexAutoLock lock(m_con_mutex);
4167         core::map<u16, RemoteClient*>::Node *n;
4168         n = m_clients.find(peer_id);
4169         // A client should exist for all peers
4170         assert(n != NULL);
4171         return n->getValue();
4172 }
4173
4174 std::wstring Server::getStatusString()
4175 {
4176         std::wostringstream os(std::ios_base::binary);
4177         os<<L"# Server: ";
4178         // Version
4179         os<<L"version="<<narrow_to_wide(VERSION_STRING);
4180         // Uptime
4181         os<<L", uptime="<<m_uptime.get();
4182         // Information about clients
4183         os<<L", clients={";
4184         for(core::map<u16, RemoteClient*>::Iterator
4185                 i = m_clients.getIterator();
4186                 i.atEnd() == false; i++)
4187         {
4188                 // Get client and check that it is valid
4189                 RemoteClient *client = i.getNode()->getValue();
4190                 assert(client->peer_id == i.getNode()->getKey());
4191                 if(client->serialization_version == SER_FMT_VER_INVALID)
4192                         continue;
4193                 // Get player
4194                 Player *player = m_env.getPlayer(client->peer_id);
4195                 // Get name of player
4196                 std::wstring name = L"unknown";
4197                 if(player != NULL)
4198                         name = narrow_to_wide(player->getName());
4199                 // Add name to information string
4200                 os<<name<<L",";
4201         }
4202         os<<L"}";
4203         if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
4204                 os<<" WARNING: Map saving is disabled."<<std::endl;
4205         return os.str();
4206 }
4207
4208
4209 void setCreativeInventory(Player *player)
4210 {
4211         player->resetInventory();
4212         
4213         // Give some good tools
4214         {
4215                 InventoryItem *item = new ToolItem("MesePick", 0);
4216                 void* r = player->inventory.addItem("main", item);
4217                 assert(r == NULL);
4218         }
4219         {
4220                 InventoryItem *item = new ToolItem("SteelPick", 0);
4221                 void* r = player->inventory.addItem("main", item);
4222                 assert(r == NULL);
4223         }
4224         {
4225                 InventoryItem *item = new ToolItem("SteelAxe", 0);
4226                 void* r = player->inventory.addItem("main", item);
4227                 assert(r == NULL);
4228         }
4229         {
4230                 InventoryItem *item = new ToolItem("SteelShovel", 0);
4231                 void* r = player->inventory.addItem("main", item);
4232                 assert(r == NULL);
4233         }
4234
4235         /*
4236                 Give materials
4237         */
4238         
4239         // CONTENT_IGNORE-terminated list
4240         u8 material_items[] = {
4241                 CONTENT_TORCH,
4242                 CONTENT_COBBLE,
4243                 CONTENT_MUD,
4244                 CONTENT_STONE,
4245                 CONTENT_SAND,
4246                 CONTENT_TREE,
4247                 CONTENT_LEAVES,
4248                 CONTENT_GLASS,
4249                 CONTENT_FENCE,
4250                 CONTENT_MESE,
4251                 CONTENT_WATERSOURCE,
4252                 CONTENT_CLOUD,
4253                 CONTENT_CHEST,
4254                 CONTENT_FURNACE,
4255                 CONTENT_SIGN_WALL,
4256                 CONTENT_IGNORE
4257         };
4258         
4259         u8 *mip = material_items;
4260         for(u16 i=0; i<PLAYER_INVENTORY_SIZE; i++)
4261         {
4262                 if(*mip == CONTENT_IGNORE)
4263                         break;
4264
4265                 InventoryItem *item = new MaterialItem(*mip, 1);
4266                 player->inventory.addItem("main", item);
4267
4268                 mip++;
4269         }
4270
4271 #if 0
4272         assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
4273         
4274         // add torch first
4275         InventoryItem *item = new MaterialItem(CONTENT_TORCH, 1);
4276         player->inventory.addItem("main", item);
4277         
4278         // Then others
4279         for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
4280         {
4281                 // Skip some materials
4282                 if(i == CONTENT_WATER || i == CONTENT_TORCH
4283                         || i == CONTENT_COALSTONE)
4284                         continue;
4285
4286                 InventoryItem *item = new MaterialItem(i, 1);
4287                 player->inventory.addItem("main", item);
4288         }
4289 #endif
4290
4291         /*// Sign
4292         {
4293                 InventoryItem *item = new MapBlockObjectItem("Sign Example text");
4294                 void* r = player->inventory.addItem("main", item);
4295                 assert(r == NULL);
4296         }*/
4297 }
4298
4299 v3f findSpawnPos(ServerMap &map)
4300 {
4301         //return v3f(50,50,50)*BS;
4302         
4303         v2s16 nodepos;
4304         s16 groundheight = 0;
4305         
4306         // Try to find a good place a few times
4307         for(s32 i=0; i<1000; i++)
4308         {
4309                 s32 range = 1 + i;
4310                 // We're going to try to throw the player to this position
4311                 nodepos = v2s16(-range + (myrand()%(range*2)),
4312                                 -range + (myrand()%(range*2)));
4313                 v2s16 sectorpos = getNodeSectorPos(nodepos);
4314                 // Get sector (NOTE: Don't get because it's slow)
4315                 //m_env.getMap().emergeSector(sectorpos);
4316                 // Get ground height at point (fallbacks to heightmap function)
4317                 groundheight = map.findGroundLevel(nodepos);
4318                 // Don't go underwater
4319                 if(groundheight < WATER_LEVEL)
4320                 {
4321                         //dstream<<"-> Underwater"<<std::endl;
4322                         continue;
4323                 }
4324                 // Don't go to high places
4325                 if(groundheight > WATER_LEVEL + 4)
4326                 {
4327                         //dstream<<"-> Underwater"<<std::endl;
4328                         continue;
4329                 }
4330
4331                 // Found a good place
4332                 //dstream<<"Searched through "<<i<<" places."<<std::endl;
4333                 break;
4334         }
4335         
4336         // If no suitable place was not found, go above water at least.
4337         if(groundheight < WATER_LEVEL)
4338                 groundheight = WATER_LEVEL;
4339
4340         return intToFloat(v3s16(
4341                         nodepos.X,
4342                         groundheight + 2,
4343                         nodepos.Y
4344                         ), BS);
4345 }
4346
4347 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4348 {
4349         /*
4350                 Try to get an existing player
4351         */
4352         Player *player = m_env.getPlayer(name);
4353         if(player != NULL)
4354         {
4355                 // If player is already connected, cancel
4356                 if(player->peer_id != 0)
4357                 {
4358                         dstream<<"emergePlayer(): Player already connected"<<std::endl;
4359                         return NULL;
4360                 }
4361
4362                 // Got one.
4363                 player->peer_id = peer_id;
4364                 
4365                 // Reset inventory to creative if in creative mode
4366                 if(g_settings.getBool("creative_mode"))
4367                 {
4368                         setCreativeInventory(player);
4369                 }
4370
4371                 return player;
4372         }
4373
4374         /*
4375                 If player with the wanted peer_id already exists, cancel.
4376         */
4377         if(m_env.getPlayer(peer_id) != NULL)
4378         {
4379                 dstream<<"emergePlayer(): Player with wrong name but same"
4380                                 " peer_id already exists"<<std::endl;
4381                 return NULL;
4382         }
4383         
4384         /*
4385                 Create a new player
4386         */
4387         {
4388                 player = new ServerRemotePlayer();
4389                 //player->peer_id = c.peer_id;
4390                 //player->peer_id = PEER_ID_INEXISTENT;
4391                 player->peer_id = peer_id;
4392                 player->updateName(name);
4393                 m_authmanager.add(name);
4394                 m_authmanager.setPassword(name, password);
4395                 m_authmanager.setPrivs(name,
4396                                 stringToPrivs(g_settings.get("default_privs")));
4397
4398                 /*
4399                         Set player position
4400                 */
4401                 
4402                 dstream<<"Server: Finding spawn place for player \""
4403                                 <<player->getName()<<"\""<<std::endl;
4404
4405                 v3f pos = findSpawnPos(m_env.getServerMap());
4406
4407                 player->setPosition(pos);
4408
4409                 /*
4410                         Add player to environment
4411                 */
4412
4413                 m_env.addPlayer(player);
4414
4415                 /*
4416                         Add stuff to inventory
4417                 */
4418                 
4419                 if(g_settings.getBool("creative_mode"))
4420                 {
4421                         setCreativeInventory(player);
4422                 }
4423                 else if(g_settings.getBool("give_initial_stuff"))
4424                 {
4425                         {
4426                                 InventoryItem *item = new ToolItem("SteelPick", 0);
4427                                 void* r = player->inventory.addItem("main", item);
4428                                 assert(r == NULL);
4429                         }
4430                         {
4431                                 InventoryItem *item = new MaterialItem(CONTENT_TORCH, 99);
4432                                 void* r = player->inventory.addItem("main", item);
4433                                 assert(r == NULL);
4434                         }
4435                         {
4436                                 InventoryItem *item = new ToolItem("SteelAxe", 0);
4437                                 void* r = player->inventory.addItem("main", item);
4438                                 assert(r == NULL);
4439                         }
4440                         {
4441                                 InventoryItem *item = new ToolItem("SteelShovel", 0);
4442                                 void* r = player->inventory.addItem("main", item);
4443                                 assert(r == NULL);
4444                         }
4445                         {
4446                                 InventoryItem *item = new MaterialItem(CONTENT_COBBLE, 99);
4447                                 void* r = player->inventory.addItem("main", item);
4448                                 assert(r == NULL);
4449                         }
4450                         /*{
4451                                 InventoryItem *item = new MaterialItem(CONTENT_MESE, 6);
4452                                 void* r = player->inventory.addItem("main", item);
4453                                 assert(r == NULL);
4454                         }
4455                         {
4456                                 InventoryItem *item = new MaterialItem(CONTENT_COALSTONE, 6);
4457                                 void* r = player->inventory.addItem("main", item);
4458                                 assert(r == NULL);
4459                         }
4460                         {
4461                                 InventoryItem *item = new MaterialItem(CONTENT_WOOD, 6);
4462                                 void* r = player->inventory.addItem("main", item);
4463                                 assert(r == NULL);
4464                         }
4465                         {
4466                                 InventoryItem *item = new CraftItem("Stick", 4);
4467                                 void* r = player->inventory.addItem("main", item);
4468                                 assert(r == NULL);
4469                         }
4470                         {
4471                                 InventoryItem *item = new ToolItem("WPick", 32000);
4472                                 void* r = player->inventory.addItem("main", item);
4473                                 assert(r == NULL);
4474                         }
4475                         {
4476                                 InventoryItem *item = new ToolItem("STPick", 32000);
4477                                 void* r = player->inventory.addItem("main", item);
4478                                 assert(r == NULL);
4479                         }*/
4480                         /*// and some signs
4481                         for(u16 i=0; i<4; i++)
4482                         {
4483                                 InventoryItem *item = new MapBlockObjectItem("Sign Example text");
4484                                 bool r = player->inventory.addItem("main", item);
4485                                 assert(r == true);
4486                         }*/
4487                         /*// Give some other stuff
4488                         {
4489                                 InventoryItem *item = new MaterialItem(CONTENT_TREE, 999);
4490                                 bool r = player->inventory.addItem("main", item);
4491                                 assert(r == true);
4492                         }*/
4493                 }
4494
4495                 return player;
4496                 
4497         } // create new player
4498 }
4499
4500 void Server::handlePeerChange(PeerChange &c)
4501 {
4502         JMutexAutoLock envlock(m_env_mutex);
4503         JMutexAutoLock conlock(m_con_mutex);
4504         
4505         if(c.type == PEER_ADDED)
4506         {
4507                 /*
4508                         Add
4509                 */
4510
4511                 // Error check
4512                 core::map<u16, RemoteClient*>::Node *n;
4513                 n = m_clients.find(c.peer_id);
4514                 // The client shouldn't already exist
4515                 assert(n == NULL);
4516
4517                 // Create client
4518                 RemoteClient *client = new RemoteClient();
4519                 client->peer_id = c.peer_id;
4520                 m_clients.insert(client->peer_id, client);
4521
4522         } // PEER_ADDED
4523         else if(c.type == PEER_REMOVED)
4524         {
4525                 /*
4526                         Delete
4527                 */
4528
4529                 // Error check
4530                 core::map<u16, RemoteClient*>::Node *n;
4531                 n = m_clients.find(c.peer_id);
4532                 // The client should exist
4533                 assert(n != NULL);
4534                 
4535                 /*
4536                         Mark objects to be not known by the client
4537                 */
4538                 RemoteClient *client = n->getValue();
4539                 // Handle objects
4540                 for(core::map<u16, bool>::Iterator
4541                                 i = client->m_known_objects.getIterator();
4542                                 i.atEnd()==false; i++)
4543                 {
4544                         // Get object
4545                         u16 id = i.getNode()->getKey();
4546                         ServerActiveObject* obj = m_env.getActiveObject(id);
4547                         
4548                         if(obj && obj->m_known_by_count > 0)
4549                                 obj->m_known_by_count--;
4550                 }
4551
4552                 // Collect information about leaving in chat
4553                 std::wstring message;
4554                 {
4555                         std::wstring name = L"unknown";
4556                         Player *player = m_env.getPlayer(c.peer_id);
4557                         if(player != NULL)
4558                                 name = narrow_to_wide(player->getName());
4559                         
4560                         message += L"*** ";
4561                         message += name;
4562                         message += L" left game";
4563                         if(c.timeout)
4564                                 message += L" (timed out)";
4565                 }
4566
4567                 /*// Delete player
4568                 {
4569                         m_env.removePlayer(c.peer_id);
4570                 }*/
4571
4572                 // Set player client disconnected
4573                 {
4574                         Player *player = m_env.getPlayer(c.peer_id);
4575                         if(player != NULL)
4576                                 player->peer_id = 0;
4577                 }
4578                 
4579                 // Delete client
4580                 delete m_clients[c.peer_id];
4581                 m_clients.remove(c.peer_id);
4582
4583                 // Send player info to all remaining clients
4584                 SendPlayerInfos();
4585                 
4586                 // Send leave chat message to all remaining clients
4587                 BroadcastChatMessage(message);
4588                 
4589         } // PEER_REMOVED
4590         else
4591         {
4592                 assert(0);
4593         }
4594 }
4595
4596 void Server::handlePeerChanges()
4597 {
4598         while(m_peer_change_queue.size() > 0)
4599         {
4600                 PeerChange c = m_peer_change_queue.pop_front();
4601
4602                 dout_server<<"Server: Handling peer change: "
4603                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4604                                 <<std::endl;
4605
4606                 handlePeerChange(c);
4607         }
4608 }
4609
4610 u64 Server::getPlayerPrivs(Player *player)
4611 {
4612         if(player==NULL)
4613                 return 0;
4614         std::string playername = player->getName();
4615         // Local player gets all privileges regardless of
4616         // what's set on their account.
4617         if(g_settings.get("name") == playername)
4618         {
4619                 return PRIV_ALL;
4620         }
4621         else
4622         {
4623                 return getPlayerAuthPrivs(playername);
4624         }
4625 }
4626
4627 void dedicated_server_loop(Server &server, bool &kill)
4628 {
4629         DSTACK(__FUNCTION_NAME);
4630         
4631         dstream<<DTIME<<std::endl;
4632         dstream<<"========================"<<std::endl;
4633         dstream<<"Running dedicated server"<<std::endl;
4634         dstream<<"========================"<<std::endl;
4635         dstream<<std::endl;
4636
4637         IntervalLimiter m_profiler_interval;
4638
4639         for(;;)
4640         {
4641                 // This is kind of a hack but can be done like this
4642                 // because server.step() is very light
4643                 {
4644                         ScopeProfiler sp(&g_profiler, "dedicated server sleep");
4645                         sleep_ms(30);
4646                 }
4647                 server.step(0.030);
4648
4649                 if(server.getShutdownRequested() || kill)
4650                 {
4651                         dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4652                         break;
4653                 }
4654
4655                 /*
4656                         Profiler
4657                 */
4658                 float profiler_print_interval =
4659                                 g_settings.getFloat("profiler_print_interval");
4660                 if(profiler_print_interval != 0)
4661                 {
4662                         if(m_profiler_interval.step(0.030, profiler_print_interval))
4663                         {
4664                                 dstream<<"Profiler:"<<std::endl;
4665                                 g_profiler.print(dstream);
4666                                 g_profiler.clear();
4667                         }
4668                 }
4669                 
4670                 /*
4671                         Player info
4672                 */
4673                 static int counter = 0;
4674                 counter--;
4675                 if(counter <= 0)
4676                 {
4677                         counter = 10;
4678
4679                         core::list<PlayerInfo> list = server.getPlayerInfo();
4680                         core::list<PlayerInfo>::Iterator i;
4681                         static u32 sum_old = 0;
4682                         u32 sum = PIChecksum(list);
4683                         if(sum != sum_old)
4684                         {
4685                                 dstream<<DTIME<<"Player info:"<<std::endl;
4686                                 for(i=list.begin(); i!=list.end(); i++)
4687                                 {
4688                                         i->PrintLine(&dstream);
4689                                 }
4690                         }
4691                         sum_old = sum;
4692                 }
4693         }
4694 }
4695
4696