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