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