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