]> git.lizzy.rs Git - minetest.git/blob - src/server.cpp
new object system
[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()<<"\t";
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                 //dstream<<"Server: Checking added and deleted active objects"<<std::endl;
1239
1240                 JMutexAutoLock envlock(m_env_mutex);
1241                 JMutexAutoLock conlock(m_con_mutex);
1242                 
1243                 // Radius inside which objects are active
1244                 s16 radius = 32;
1245
1246                 for(core::map<u16, RemoteClient*>::Iterator
1247                         i = m_clients.getIterator();
1248                         i.atEnd() == false; i++)
1249                 {
1250                         RemoteClient *client = i.getNode()->getValue();
1251                         Player *player = m_env.getPlayer(client->peer_id);
1252                         if(player==NULL)
1253                         {
1254                                 dstream<<"WARNING: "<<__FUNCTION_NAME<<": Client "<<client->peer_id
1255                                                 <<" has no associated player"<<std::endl;
1256                                 continue;
1257                         }
1258                         v3s16 pos = floatToInt(player->getPosition(), BS);
1259
1260                         core::map<u16, bool> removed_objects;
1261                         core::map<u16, bool> added_objects;
1262                         m_env.getRemovedActiveObjects(pos, radius,
1263                                         client->m_known_objects, removed_objects);
1264                         m_env.getAddedActiveObjects(pos, radius,
1265                                         client->m_known_objects, added_objects);
1266                         
1267                         // Ignore if nothing happened
1268                         if(removed_objects.size() == 0 && added_objects.size() == 0)
1269                         {
1270                                 //dstream<<"INFO: active objects: none changed"<<std::endl;
1271                                 continue;
1272                         }
1273                         
1274                         std::string data_buffer;
1275
1276                         char buf[4];
1277                         
1278                         // Handle removed objects
1279                         writeU16((u8*)buf, removed_objects.size());
1280                         data_buffer.append(buf, 2);
1281                         for(core::map<u16, bool>::Iterator
1282                                         i = removed_objects.getIterator();
1283                                         i.atEnd()==false; i++)
1284                         {
1285                                 // Get object
1286                                 u16 id = i.getNode()->getKey();
1287                                 ServerActiveObject* obj = m_env.getActiveObject(id);
1288
1289                                 // Add to data buffer for sending
1290                                 writeU16((u8*)buf, i.getNode()->getKey());
1291                                 data_buffer.append(buf, 2);
1292                                 
1293                                 // Remove from known objects
1294                                 client->m_known_objects.remove(i.getNode()->getKey());
1295
1296                                 if(obj && obj->m_known_by_count > 0)
1297                                         obj->m_known_by_count--;
1298                         }
1299
1300                         // Handle added objects
1301                         writeU16((u8*)buf, added_objects.size());
1302                         data_buffer.append(buf, 2);
1303                         for(core::map<u16, bool>::Iterator
1304                                         i = added_objects.getIterator();
1305                                         i.atEnd()==false; i++)
1306                         {
1307                                 // Get object
1308                                 u16 id = i.getNode()->getKey();
1309                                 ServerActiveObject* obj = m_env.getActiveObject(id);
1310                                 
1311                                 // Get object type
1312                                 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1313                                 if(obj == NULL)
1314                                         dstream<<"WARNING: "<<__FUNCTION_NAME
1315                                                         <<": NULL object"<<std::endl;
1316                                 else
1317                                         type = obj->getType();
1318
1319                                 // Add to data buffer for sending
1320                                 writeU16((u8*)buf, id);
1321                                 data_buffer.append(buf, 2);
1322                                 writeU8((u8*)buf, type);
1323                                 data_buffer.append(buf, 1);
1324
1325                                 data_buffer.append(serializeLongString(
1326                                                 obj->getClientInitializationData()));
1327
1328                                 // Add to known objects
1329                                 client->m_known_objects.insert(i.getNode()->getKey(), false);
1330
1331                                 if(obj)
1332                                         obj->m_known_by_count++;
1333                         }
1334
1335                         // Send packet
1336                         SharedBuffer<u8> reply(2 + data_buffer.size());
1337                         writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1338                         memcpy((char*)&reply[2], data_buffer.c_str(),
1339                                         data_buffer.size());
1340                         // Send as reliable
1341                         m_con.Send(client->peer_id, 0, reply, true);
1342
1343                         dstream<<"INFO: Server: Sent object remove/add: "
1344                                         <<removed_objects.size()<<" removed, "
1345                                         <<added_objects.size()<<" added, "
1346                                         <<"packet size is "<<reply.getSize()<<std::endl;
1347                 }
1348
1349 #if 0
1350                 /*
1351                         Collect a list of all the objects known by the clients
1352                         and report it back to the environment.
1353                 */
1354
1355                 core::map<u16, bool> all_known_objects;
1356
1357                 for(core::map<u16, RemoteClient*>::Iterator
1358                         i = m_clients.getIterator();
1359                         i.atEnd() == false; i++)
1360                 {
1361                         RemoteClient *client = i.getNode()->getValue();
1362                         // Go through all known objects of client
1363                         for(core::map<u16, bool>::Iterator
1364                                         i = client->m_known_objects.getIterator();
1365                                         i.atEnd()==false; i++)
1366                         {
1367                                 u16 id = i.getNode()->getKey();
1368                                 all_known_objects[id] = true;
1369                         }
1370                 }
1371                 
1372                 m_env.setKnownActiveObjects(whatever);
1373 #endif
1374
1375         }
1376
1377         /*
1378                 Send object messages
1379         */
1380         {
1381                 JMutexAutoLock envlock(m_env_mutex);
1382                 JMutexAutoLock conlock(m_con_mutex);
1383
1384                 // Key = object id
1385                 // Value = data sent by object
1386                 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1387
1388                 // Get active object messages from environment
1389                 for(;;)
1390                 {
1391                         ActiveObjectMessage aom = m_env.getActiveObjectMessage();
1392                         if(aom.id == 0)
1393                                 break;
1394                         
1395                         core::list<ActiveObjectMessage>* message_list = NULL;
1396                         core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1397                         n = buffered_messages.find(aom.id);
1398                         if(n == NULL)
1399                         {
1400                                 message_list = new core::list<ActiveObjectMessage>;
1401                                 buffered_messages.insert(aom.id, message_list);
1402                         }
1403                         else
1404                         {
1405                                 message_list = n->getValue();
1406                         }
1407                         message_list->push_back(aom);
1408                 }
1409                 
1410                 // Route data to every client
1411                 for(core::map<u16, RemoteClient*>::Iterator
1412                         i = m_clients.getIterator();
1413                         i.atEnd()==false; i++)
1414                 {
1415                         RemoteClient *client = i.getNode()->getValue();
1416                         std::string reliable_data;
1417                         std::string unreliable_data;
1418                         // Go through all objects in message buffer
1419                         for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1420                                         j = buffered_messages.getIterator();
1421                                         j.atEnd()==false; j++)
1422                         {
1423                                 // If object is not known by client, skip it
1424                                 u16 id = j.getNode()->getKey();
1425                                 if(client->m_known_objects.find(id) == NULL)
1426                                         continue;
1427                                 // Get message list of object
1428                                 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1429                                 // Go through every message
1430                                 for(core::list<ActiveObjectMessage>::Iterator
1431                                                 k = list->begin(); k != list->end(); k++)
1432                                 {
1433                                         // Compose the full new data with header
1434                                         ActiveObjectMessage aom = *k;
1435                                         std::string new_data;
1436                                         // Add object id
1437                                         char buf[2];
1438                                         writeU16((u8*)&buf[0], aom.id);
1439                                         new_data.append(buf, 2);
1440                                         // Add data
1441                                         new_data += serializeString(aom.datastring);
1442                                         // Add data to buffer
1443                                         if(aom.reliable)
1444                                                 reliable_data += new_data;
1445                                         else
1446                                                 unreliable_data += new_data;
1447                                 }
1448                         }
1449                         /*
1450                                 reliable_data and unreliable_data are now ready.
1451                                 Send them.
1452                         */
1453                         if(reliable_data.size() > 0)
1454                         {
1455                                 SharedBuffer<u8> reply(2 + reliable_data.size());
1456                                 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1457                                 memcpy((char*)&reply[2], reliable_data.c_str(),
1458                                                 reliable_data.size());
1459                                 // Send as reliable
1460                                 m_con.Send(client->peer_id, 0, reply, true);
1461                         }
1462                         if(unreliable_data.size() > 0)
1463                         {
1464                                 SharedBuffer<u8> reply(2 + unreliable_data.size());
1465                                 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1466                                 memcpy((char*)&reply[2], unreliable_data.c_str(),
1467                                                 unreliable_data.size());
1468                                 // Send as unreliable
1469                                 m_con.Send(client->peer_id, 0, reply, false);
1470                         }
1471
1472                         /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1473                         {
1474                                 dstream<<"INFO: Server: Size of object message data: "
1475                                                 <<"reliable: "<<reliable_data.size()
1476                                                 <<", unreliable: "<<unreliable_data.size()
1477                                                 <<std::endl;
1478                         }*/
1479                 }
1480
1481                 // Clear buffered_messages
1482                 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1483                                 i = buffered_messages.getIterator();
1484                                 i.atEnd()==false; i++)
1485                 {
1486                         delete i.getNode()->getValue();
1487                 }
1488         }
1489
1490         } // enable_experimental
1491
1492         /*
1493                 Send queued-for-sending map edit events.
1494         */
1495         {
1496                 while(m_unsent_map_edit_queue.size() != 0)
1497                 {
1498                         MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1499
1500                         if(event->type == MEET_ADDNODE)
1501                         {
1502                                 dstream<<"Server: MEET_ADDNODE"<<std::endl;
1503                                 sendAddNode(event->p, event->n, event->already_known_by_peer);
1504                         }
1505                         else if(event->type == MEET_REMOVENODE)
1506                         {
1507                                 dstream<<"Server: MEET_REMOVENODE"<<std::endl;
1508                                 sendRemoveNode(event->p, event->already_known_by_peer);
1509                         }
1510                         else if(event->type == MEET_OTHER)
1511                         {
1512                                 dstream<<"WARNING: Server: MEET_OTHER not implemented"
1513                                                 <<std::endl;
1514                         }
1515                         else
1516                         {
1517                                 dstream<<"WARNING: Server: Unknown MapEditEvent "
1518                                                 <<((u32)event->type)<<std::endl;
1519                         }
1520
1521                         delete event;
1522                 }
1523         }
1524
1525         /*
1526                 Send object positions
1527                 TODO: Get rid of MapBlockObjects
1528         */
1529         {
1530                 float &counter = m_objectdata_timer;
1531                 counter += dtime;
1532                 if(counter >= g_settings.getFloat("objectdata_interval"))
1533                 {
1534                         JMutexAutoLock lock1(m_env_mutex);
1535                         JMutexAutoLock lock2(m_con_mutex);
1536                         SendObjectData(counter);
1537
1538                         counter = 0.0;
1539                 }
1540         }
1541         
1542         /*
1543                 Step node metadata
1544         */
1545         {
1546                 JMutexAutoLock envlock(m_env_mutex);
1547                 JMutexAutoLock conlock(m_con_mutex);
1548                 
1549                 core::map<v3s16, MapBlock*> changed_blocks;
1550                 m_env.getMap().nodeMetadataStep(dtime, changed_blocks);
1551
1552                 for(core::map<v3s16, MapBlock*>::Iterator
1553                                 i = changed_blocks.getIterator();
1554                                 i.atEnd() == false; i++)
1555                 {
1556                         MapBlock *block = i.getNode()->getValue();
1557
1558                         for(core::map<u16, RemoteClient*>::Iterator
1559                                 i = m_clients.getIterator();
1560                                 i.atEnd()==false; i++)
1561                         {
1562                                 RemoteClient *client = i.getNode()->getValue();
1563                                 client->SetBlockNotSent(block->getPos());
1564                         }
1565                 }
1566         }
1567                 
1568         /*
1569                 Trigger emergethread (it somehow gets to a non-triggered but
1570                 bysy state sometimes)
1571         */
1572         {
1573                 float &counter = m_emergethread_trigger_timer;
1574                 counter += dtime;
1575                 if(counter >= 2.0)
1576                 {
1577                         counter = 0.0;
1578                         
1579                         m_emergethread.trigger();
1580                 }
1581         }
1582
1583         // Save map
1584         {
1585                 float &counter = m_savemap_timer;
1586                 counter += dtime;
1587                 if(counter >= g_settings.getFloat("server_map_save_interval"))
1588                 {
1589                         counter = 0.0;
1590
1591                         JMutexAutoLock lock(m_env_mutex);
1592
1593                         if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == true)
1594                         {
1595                                 // Save only changed parts
1596                                 m_env.getMap().save(true);
1597
1598                                 // Delete unused sectors
1599                                 u32 deleted_count = m_env.getMap().deleteUnusedSectors(
1600                                                 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1601                                 if(deleted_count > 0)
1602                                 {
1603                                         dout_server<<"Server: Unloaded "<<deleted_count
1604                                                         <<" sectors from memory"<<std::endl;
1605                                 }
1606
1607                                 // Save players
1608                                 m_env.serializePlayers(m_mapsavedir);
1609                         }
1610                 }
1611         }
1612 }
1613
1614 void Server::Receive()
1615 {
1616         DSTACK(__FUNCTION_NAME);
1617         u32 data_maxsize = 10000;
1618         Buffer<u8> data(data_maxsize);
1619         u16 peer_id;
1620         u32 datasize;
1621         try{
1622                 {
1623                         JMutexAutoLock conlock(m_con_mutex);
1624                         datasize = m_con.Receive(peer_id, *data, data_maxsize);
1625                 }
1626
1627                 // This has to be called so that the client list gets synced
1628                 // with the peer list of the connection
1629                 handlePeerChanges();
1630
1631                 ProcessData(*data, datasize, peer_id);
1632         }
1633         catch(con::InvalidIncomingDataException &e)
1634         {
1635                 derr_server<<"Server::Receive(): "
1636                                 "InvalidIncomingDataException: what()="
1637                                 <<e.what()<<std::endl;
1638         }
1639         catch(con::PeerNotFoundException &e)
1640         {
1641                 //NOTE: This is not needed anymore
1642                 
1643                 // The peer has been disconnected.
1644                 // Find the associated player and remove it.
1645
1646                 /*JMutexAutoLock envlock(m_env_mutex);
1647
1648                 dout_server<<"ServerThread: peer_id="<<peer_id
1649                                 <<" has apparently closed connection. "
1650                                 <<"Removing player."<<std::endl;
1651
1652                 m_env.removePlayer(peer_id);*/
1653         }
1654 }
1655
1656 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1657 {
1658         DSTACK(__FUNCTION_NAME);
1659         // Environment is locked first.
1660         JMutexAutoLock envlock(m_env_mutex);
1661         JMutexAutoLock conlock(m_con_mutex);
1662         
1663         con::Peer *peer;
1664         try{
1665                 peer = m_con.GetPeer(peer_id);
1666         }
1667         catch(con::PeerNotFoundException &e)
1668         {
1669                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1670                                 <<peer_id<<" not found"<<std::endl;
1671                 return;
1672         }
1673         
1674         u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1675
1676         try
1677         {
1678
1679         if(datasize < 2)
1680                 return;
1681
1682         ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1683         
1684         if(command == TOSERVER_INIT)
1685         {
1686                 // [0] u16 TOSERVER_INIT
1687                 // [2] u8 SER_FMT_VER_HIGHEST
1688                 // [3] u8[20] player_name
1689
1690                 if(datasize < 3)
1691                         return;
1692
1693                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1694                                 <<peer->id<<std::endl;
1695
1696                 // First byte after command is maximum supported
1697                 // serialization version
1698                 u8 client_max = data[2];
1699                 u8 our_max = SER_FMT_VER_HIGHEST;
1700                 // Use the highest version supported by both
1701                 u8 deployed = core::min_(client_max, our_max);
1702                 // If it's lower than the lowest supported, give up.
1703                 if(deployed < SER_FMT_VER_LOWEST)
1704                         deployed = SER_FMT_VER_INVALID;
1705
1706                 //peer->serialization_version = deployed;
1707                 getClient(peer->id)->pending_serialization_version = deployed;
1708
1709                 if(deployed == SER_FMT_VER_INVALID)
1710                 {
1711                         derr_server<<DTIME<<"Server: Cannot negotiate "
1712                                         "serialization version with peer "
1713                                         <<peer_id<<std::endl;
1714                         return;
1715                 }
1716
1717                 /*
1718                         Set up player
1719                 */
1720                 
1721                 // Get player name
1722                 const u32 playername_size = 20;
1723                 char playername[playername_size];
1724                 for(u32 i=0; i<playername_size-1; i++)
1725                 {
1726                         playername[i] = data[3+i];
1727                 }
1728                 playername[playername_size-1] = 0;
1729                 
1730                 // Get player
1731                 Player *player = emergePlayer(playername, "", peer_id);
1732                 //Player *player = m_env.getPlayer(peer_id);
1733
1734                 /*{
1735                         // DEBUG: Test serialization
1736                         std::ostringstream test_os;
1737                         player->serialize(test_os);
1738                         dstream<<"Player serialization test: \""<<test_os.str()
1739                                         <<"\""<<std::endl;
1740                         std::istringstream test_is(test_os.str());
1741                         player->deSerialize(test_is);
1742                 }*/
1743
1744                 // If failed, cancel
1745                 if(player == NULL)
1746                 {
1747                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
1748                                         <<": failed to emerge player"<<std::endl;
1749                         return;
1750                 }
1751
1752                 /*
1753                 // If a client is already connected to the player, cancel
1754                 if(player->peer_id != 0)
1755                 {
1756                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
1757                                         <<" tried to connect to "
1758                                         "an already connected player (peer_id="
1759                                         <<player->peer_id<<")"<<std::endl;
1760                         return;
1761                 }
1762                 // Set client of player
1763                 player->peer_id = peer_id;
1764                 */
1765
1766                 // Check if player doesn't exist
1767                 if(player == NULL)
1768                         throw con::InvalidIncomingDataException
1769                                 ("Server::ProcessData(): INIT: Player doesn't exist");
1770
1771                 /*// update name if it was supplied
1772                 if(datasize >= 20+3)
1773                 {
1774                         data[20+3-1] = 0;
1775                         player->updateName((const char*)&data[3]);
1776                 }*/
1777
1778                 // Now answer with a TOCLIENT_INIT
1779                 
1780                 SharedBuffer<u8> reply(2+1+6+8);
1781                 writeU16(&reply[0], TOCLIENT_INIT);
1782                 writeU8(&reply[2], deployed);
1783                 writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
1784                 //writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
1785                 
1786                 // Send as reliable
1787                 m_con.Send(peer_id, 0, reply, true);
1788
1789                 return;
1790         }
1791         if(command == TOSERVER_INIT2)
1792         {
1793                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
1794                                 <<peer->id<<std::endl;
1795
1796
1797                 getClient(peer->id)->serialization_version
1798                                 = getClient(peer->id)->pending_serialization_version;
1799
1800                 /*
1801                         Send some initialization data
1802                 */
1803                 
1804                 // Send player info to all players
1805                 SendPlayerInfos();
1806
1807                 // Send inventory to player
1808                 SendInventory(peer->id);
1809                 
1810                 // Send time of day
1811                 {
1812                         SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1813                                         m_time_of_day.get());
1814                         m_con.Send(peer->id, 0, data, true);
1815                 }
1816                 
1817                 // Send information about server to player in chat
1818                 SendChatMessage(peer_id, getStatusString());
1819                 
1820                 // Send information about joining in chat
1821                 {
1822                         std::wstring name = L"unknown";
1823                         Player *player = m_env.getPlayer(peer_id);
1824                         if(player != NULL)
1825                                 name = narrow_to_wide(player->getName());
1826                         
1827                         std::wstring message;
1828                         message += L"*** ";
1829                         message += name;
1830                         message += L" joined game";
1831                         BroadcastChatMessage(message);
1832                 }
1833
1834                 return;
1835         }
1836
1837         if(peer_ser_ver == SER_FMT_VER_INVALID)
1838         {
1839                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
1840                                 " serialization format invalid or not initialized."
1841                                 " Skipping incoming command="<<command<<std::endl;
1842                 return;
1843         }
1844         
1845         Player *player = m_env.getPlayer(peer_id);
1846
1847         if(player == NULL){
1848                 derr_server<<"Server::ProcessData(): Cancelling: "
1849                                 "No player for peer_id="<<peer_id
1850                                 <<std::endl;
1851                 return;
1852         }
1853         if(command == TOSERVER_PLAYERPOS)
1854         {
1855                 if(datasize < 2+12+12+4+4)
1856                         return;
1857         
1858                 u32 start = 0;
1859                 v3s32 ps = readV3S32(&data[start+2]);
1860                 v3s32 ss = readV3S32(&data[start+2+12]);
1861                 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1862                 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1863                 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1864                 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1865                 pitch = wrapDegrees(pitch);
1866                 yaw = wrapDegrees(yaw);
1867                 player->setPosition(position);
1868                 player->setSpeed(speed);
1869                 player->setPitch(pitch);
1870                 player->setYaw(yaw);
1871                 
1872                 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1873                                 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1874                                 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1875         }
1876         else if(command == TOSERVER_GOTBLOCKS)
1877         {
1878                 if(datasize < 2+1)
1879                         return;
1880                 
1881                 /*
1882                         [0] u16 command
1883                         [2] u8 count
1884                         [3] v3s16 pos_0
1885                         [3+6] v3s16 pos_1
1886                         ...
1887                 */
1888
1889                 u16 count = data[2];
1890                 for(u16 i=0; i<count; i++)
1891                 {
1892                         if((s16)datasize < 2+1+(i+1)*6)
1893                                 throw con::InvalidIncomingDataException
1894                                         ("GOTBLOCKS length is too short");
1895                         v3s16 p = readV3S16(&data[2+1+i*6]);
1896                         /*dstream<<"Server: GOTBLOCKS ("
1897                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1898                         RemoteClient *client = getClient(peer_id);
1899                         client->GotBlock(p);
1900                 }
1901         }
1902         else if(command == TOSERVER_DELETEDBLOCKS)
1903         {
1904                 if(datasize < 2+1)
1905                         return;
1906                 
1907                 /*
1908                         [0] u16 command
1909                         [2] u8 count
1910                         [3] v3s16 pos_0
1911                         [3+6] v3s16 pos_1
1912                         ...
1913                 */
1914
1915                 u16 count = data[2];
1916                 for(u16 i=0; i<count; i++)
1917                 {
1918                         if((s16)datasize < 2+1+(i+1)*6)
1919                                 throw con::InvalidIncomingDataException
1920                                         ("DELETEDBLOCKS length is too short");
1921                         v3s16 p = readV3S16(&data[2+1+i*6]);
1922                         /*dstream<<"Server: DELETEDBLOCKS ("
1923                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1924                         RemoteClient *client = getClient(peer_id);
1925                         client->SetBlockNotSent(p);
1926                 }
1927         }
1928         else if(command == TOSERVER_CLICK_OBJECT)
1929         {
1930                 if(datasize < 13)
1931                         return;
1932
1933                 /*
1934                         [0] u16 command
1935                         [2] u8 button (0=left, 1=right)
1936                         [3] v3s16 block
1937                         [9] s16 id
1938                         [11] u16 item
1939                 */
1940                 u8 button = readU8(&data[2]);
1941                 v3s16 p;
1942                 p.X = readS16(&data[3]);
1943                 p.Y = readS16(&data[5]);
1944                 p.Z = readS16(&data[7]);
1945                 s16 id = readS16(&data[9]);
1946                 //u16 item_i = readU16(&data[11]);
1947
1948                 MapBlock *block = NULL;
1949                 try
1950                 {
1951                         block = m_env.getMap().getBlockNoCreate(p);
1952                 }
1953                 catch(InvalidPositionException &e)
1954                 {
1955                         derr_server<<"CLICK_OBJECT block not found"<<std::endl;
1956                         return;
1957                 }
1958
1959                 MapBlockObject *obj = block->getObject(id);
1960
1961                 if(obj == NULL)
1962                 {
1963                         derr_server<<"CLICK_OBJECT object not found"<<std::endl;
1964                         return;
1965                 }
1966
1967                 //TODO: Check that object is reasonably close
1968                 
1969                 // Left click
1970                 if(button == 0)
1971                 {
1972                         InventoryList *ilist = player->inventory.getList("main");
1973                         if(g_settings.getBool("creative_mode") == false && ilist != NULL)
1974                         {
1975                         
1976                                 // Skip if inventory has no free space
1977                                 if(ilist->getUsedSlots() == ilist->getSize())
1978                                 {
1979                                         dout_server<<"Player inventory has no free space"<<std::endl;
1980                                         return;
1981                                 }
1982                                 
1983                                 /*
1984                                         Create the inventory item
1985                                 */
1986                                 InventoryItem *item = NULL;
1987                                 // If it is an item-object, take the item from it
1988                                 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
1989                                 {
1990                                         item = ((ItemObject*)obj)->createInventoryItem();
1991                                 }
1992                                 // Else create an item of the object
1993                                 else
1994                                 {
1995                                         item = new MapBlockObjectItem
1996                                                         (obj->getInventoryString());
1997                                 }
1998                                 
1999                                 // Add to inventory and send inventory
2000                                 ilist->addItem(item);
2001                                 SendInventory(player->peer_id);
2002                         }
2003
2004                         // Remove from block
2005                         block->removeObject(id);
2006                 }
2007         }
2008         else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2009         {
2010                 if(datasize < 7)
2011                         return;
2012
2013                 /*
2014                         length: 7
2015                         [0] u16 command
2016                         [2] u8 button (0=left, 1=right)
2017                         [3] u16 id
2018                         [5] u16 item
2019                 */
2020                 u8 button = readU8(&data[2]);
2021                 u16 id = readS16(&data[3]);
2022                 //u16 item_i = readU16(&data[11]);
2023         
2024                 ServerActiveObject *obj = m_env.getActiveObject(id);
2025
2026                 if(obj == NULL)
2027                 {
2028                         derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2029                                         <<std::endl;
2030                         return;
2031                 }
2032
2033                 //TODO: Check that object is reasonably close
2034                 
2035                 // Left click, pick object up (usually)
2036                 if(button == 0)
2037                 {
2038                         InventoryList *ilist = player->inventory.getList("main");
2039                         if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2040                         {
2041                         
2042                                 // Skip if inventory has no free space
2043                                 if(ilist->getUsedSlots() == ilist->getSize())
2044                                 {
2045                                         dout_server<<"Player inventory has no free space"<<std::endl;
2046                                         return;
2047                                 }
2048                                 
2049                                 /*
2050                                         Create the inventory item
2051                                 */
2052                                 InventoryItem *item = NULL;
2053                                 // If it is an item-object, take the item from it
2054                                 if(obj->getType() == ACTIVEOBJECT_TYPE_ITEM
2055                                                 && obj->m_removed == false)
2056                                 {
2057                                         item = ((ItemSAO*)obj)->createInventoryItem();
2058                                 }
2059                                 
2060                                 if(item)
2061                                 {
2062                                         // Add to inventory and send inventory
2063                                         ilist->addItem(item);
2064                                         SendInventory(player->peer_id);
2065                                 }
2066                         }
2067
2068                         // Remove object from environment
2069                         obj->m_removed = true;
2070                 }
2071         }
2072         else if(command == TOSERVER_GROUND_ACTION)
2073         {
2074                 if(datasize < 17)
2075                         return;
2076                 /*
2077                         length: 17
2078                         [0] u16 command
2079                         [2] u8 action
2080                         [3] v3s16 nodepos_undersurface
2081                         [9] v3s16 nodepos_abovesurface
2082                         [15] u16 item
2083                         actions:
2084                         0: start digging
2085                         1: place block
2086                         2: stop digging (all parameters ignored)
2087                         3: digging completed
2088                 */
2089                 u8 action = readU8(&data[2]);
2090                 v3s16 p_under;
2091                 p_under.X = readS16(&data[3]);
2092                 p_under.Y = readS16(&data[5]);
2093                 p_under.Z = readS16(&data[7]);
2094                 v3s16 p_over;
2095                 p_over.X = readS16(&data[9]);
2096                 p_over.Y = readS16(&data[11]);
2097                 p_over.Z = readS16(&data[13]);
2098                 u16 item_i = readU16(&data[15]);
2099
2100                 //TODO: Check that target is reasonably close
2101                 
2102                 /*
2103                         0: start digging
2104                 */
2105                 if(action == 0)
2106                 {
2107                         /*
2108                                 NOTE: This can be used in the future to check if
2109                                 somebody is cheating, by checking the timing.
2110                         */
2111                 } // action == 0
2112
2113                 /*
2114                         2: stop digging
2115                 */
2116                 else if(action == 2)
2117                 {
2118 #if 0
2119                         RemoteClient *client = getClient(peer->id);
2120                         JMutexAutoLock digmutex(client->m_dig_mutex);
2121                         client->m_dig_tool_item = -1;
2122 #endif
2123                 }
2124
2125                 /*
2126                         3: Digging completed
2127                 */
2128                 else if(action == 3)
2129                 {
2130                         // Mandatory parameter; actually used for nothing
2131                         core::map<v3s16, MapBlock*> modified_blocks;
2132
2133                         u8 material;
2134                         u8 mineral = MINERAL_NONE;
2135
2136                         bool cannot_remove_node = false;
2137
2138                         try
2139                         {
2140                                 MapNode n = m_env.getMap().getNode(p_under);
2141                                 // Get mineral
2142                                 mineral = n.getMineral();
2143                                 // Get material at position
2144                                 material = n.d;
2145                                 // If not yet cancelled
2146                                 if(cannot_remove_node == false)
2147                                 {
2148                                         // If it's not diggable, do nothing
2149                                         if(content_diggable(material) == false)
2150                                         {
2151                                                 derr_server<<"Server: Not finishing digging: "
2152                                                                 <<"Node not diggable"
2153                                                                 <<std::endl;
2154                                                 cannot_remove_node = true;
2155                                         }
2156                                 }
2157                                 // If not yet cancelled
2158                                 if(cannot_remove_node == false)
2159                                 {
2160                                         // Get node metadata
2161                                         NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2162                                         if(meta && meta->nodeRemovalDisabled() == true)
2163                                         {
2164                                                 derr_server<<"Server: Not finishing digging: "
2165                                                                 <<"Node metadata disables removal"
2166                                                                 <<std::endl;
2167                                                 cannot_remove_node = true;
2168                                         }
2169                                 }
2170                         }
2171                         catch(InvalidPositionException &e)
2172                         {
2173                                 derr_server<<"Server: Not finishing digging: Node not found."
2174                                                 <<" Adding block to emerge queue."
2175                                                 <<std::endl;
2176                                 m_emerge_queue.addBlock(peer_id,
2177                                                 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2178                                 cannot_remove_node = true;
2179                         }
2180
2181                         /*
2182                                 If node can't be removed, set block to be re-sent to
2183                                 client and quit.
2184                         */
2185                         if(cannot_remove_node)
2186                         {
2187                                 derr_server<<"Server: Not finishing digging."<<std::endl;
2188
2189                                 // Client probably has wrong data.
2190                                 // Set block not sent, so that client will get
2191                                 // a valid one.
2192                                 dstream<<"Client "<<peer_id<<" tried to dig "
2193                                                 <<"node; but node cannot be removed."
2194                                                 <<" setting MapBlock not sent."<<std::endl;
2195                                 RemoteClient *client = getClient(peer_id);
2196                                 v3s16 blockpos = getNodeBlockPos(p_under);
2197                                 client->SetBlockNotSent(blockpos);
2198                                         
2199                                 return;
2200                         }
2201                         
2202                         /*
2203                                 Send the removal to all other clients.
2204                                 - If other player is close, send REMOVENODE
2205                                 - Otherwise set blocks not sent
2206                         */
2207                         core::list<u16> far_players;
2208                         sendRemoveNode(p_under, peer_id, &far_players, 100);
2209                         
2210                         /*
2211                                 Update and send inventory
2212                         */
2213
2214                         if(g_settings.getBool("creative_mode") == false)
2215                         {
2216                                 /*
2217                                         Wear out tool
2218                                 */
2219                                 InventoryList *mlist = player->inventory.getList("main");
2220                                 if(mlist != NULL)
2221                                 {
2222                                         InventoryItem *item = mlist->getItem(item_i);
2223                                         if(item && (std::string)item->getName() == "ToolItem")
2224                                         {
2225                                                 ToolItem *titem = (ToolItem*)item;
2226                                                 std::string toolname = titem->getToolName();
2227
2228                                                 // Get digging properties for material and tool
2229                                                 DiggingProperties prop =
2230                                                                 getDiggingProperties(material, toolname);
2231
2232                                                 if(prop.diggable == false)
2233                                                 {
2234                                                         derr_server<<"Server: WARNING: Player digged"
2235                                                                         <<" with impossible material + tool"
2236                                                                         <<" combination"<<std::endl;
2237                                                 }
2238                                                 
2239                                                 bool weared_out = titem->addWear(prop.wear);
2240
2241                                                 if(weared_out)
2242                                                 {
2243                                                         mlist->deleteItem(item_i);
2244                                                 }
2245                                         }
2246                                 }
2247
2248                                 /*
2249                                         Add dug item to inventory
2250                                 */
2251
2252                                 InventoryItem *item = NULL;
2253
2254                                 if(mineral != MINERAL_NONE)
2255                                         item = getDiggedMineralItem(mineral);
2256                                 
2257                                 // If not mineral
2258                                 if(item == NULL)
2259                                 {
2260                                         std::string &dug_s = content_features(material).dug_item;
2261                                         if(dug_s != "")
2262                                         {
2263                                                 std::istringstream is(dug_s, std::ios::binary);
2264                                                 item = InventoryItem::deSerialize(is);
2265                                         }
2266                                 }
2267                                 
2268                                 if(item != NULL)
2269                                 {
2270                                         // Add a item to inventory
2271                                         player->inventory.addItem("main", item);
2272
2273                                         // Send inventory
2274                                         SendInventory(player->peer_id);
2275                                 }
2276                         }
2277
2278                         /*
2279                                 Remove the node
2280                                 (this takes some time so it is done after the quick stuff)
2281                         */
2282                         m_ignore_map_edit_events = true;
2283                         m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2284                         m_ignore_map_edit_events = false;
2285                         
2286                         /*
2287                                 Set blocks not sent to far players
2288                         */
2289                         for(core::list<u16>::Iterator
2290                                         i = far_players.begin();
2291                                         i != far_players.end(); i++)
2292                         {
2293                                 u16 peer_id = *i;
2294                                 RemoteClient *client = getClient(peer_id);
2295                                 if(client==NULL)
2296                                         continue;
2297                                 client->SetBlocksNotSent(modified_blocks);
2298                         }
2299                 }
2300                 
2301                 /*
2302                         1: place block
2303                 */
2304                 else if(action == 1)
2305                 {
2306
2307                         InventoryList *ilist = player->inventory.getList("main");
2308                         if(ilist == NULL)
2309                                 return;
2310
2311                         // Get item
2312                         InventoryItem *item = ilist->getItem(item_i);
2313                         
2314                         // If there is no item, it is not possible to add it anywhere
2315                         if(item == NULL)
2316                                 return;
2317                         
2318                         /*
2319                                 Handle material items
2320                         */
2321                         if(std::string("MaterialItem") == item->getName())
2322                         {
2323                                 try{
2324                                         // Don't add a node if this is not a free space
2325                                         MapNode n2 = m_env.getMap().getNode(p_over);
2326                                         if(content_buildable_to(n2.d) == false)
2327                                         {
2328                                                 // Client probably has wrong data.
2329                                                 // Set block not sent, so that client will get
2330                                                 // a valid one.
2331                                                 dstream<<"Client "<<peer_id<<" tried to place"
2332                                                                 <<" node in invalid position; setting"
2333                                                                 <<" MapBlock not sent."<<std::endl;
2334                                                 RemoteClient *client = getClient(peer_id);
2335                                                 v3s16 blockpos = getNodeBlockPos(p_over);
2336                                                 client->SetBlockNotSent(blockpos);
2337                                                 return;
2338                                         }
2339                                 }
2340                                 catch(InvalidPositionException &e)
2341                                 {
2342                                         derr_server<<"Server: Ignoring ADDNODE: Node not found"
2343                                                         <<" Adding block to emerge queue."
2344                                                         <<std::endl;
2345                                         m_emerge_queue.addBlock(peer_id,
2346                                                         getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2347                                         return;
2348                                 }
2349
2350                                 // Reset build time counter
2351                                 getClient(peer->id)->m_time_from_building = 0.0;
2352                                 
2353                                 // Create node data
2354                                 MaterialItem *mitem = (MaterialItem*)item;
2355                                 MapNode n;
2356                                 n.d = mitem->getMaterial();
2357                                 if(content_features(n.d).wall_mounted)
2358                                         n.dir = packDir(p_under - p_over);
2359                                 
2360                                 /*
2361                                         Send to all players
2362                                 */
2363                                 core::list<u16> far_players;
2364                                 sendAddNode(p_over, n, 0, &far_players, 100);
2365                                 
2366                                 /*
2367                                         Handle inventory
2368                                 */
2369                                 InventoryList *ilist = player->inventory.getList("main");
2370                                 if(g_settings.getBool("creative_mode") == false && ilist)
2371                                 {
2372                                         // Remove from inventory and send inventory
2373                                         if(mitem->getCount() == 1)
2374                                                 ilist->deleteItem(item_i);
2375                                         else
2376                                                 mitem->remove(1);
2377                                         // Send inventory
2378                                         SendInventory(peer_id);
2379                                 }
2380                                 
2381                                 /*
2382                                         Add node.
2383
2384                                         This takes some time so it is done after the quick stuff
2385                                 */
2386                                 core::map<v3s16, MapBlock*> modified_blocks;
2387                                 m_ignore_map_edit_events = true;
2388                                 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2389                                 m_ignore_map_edit_events = false;
2390                                 
2391                                 /*
2392                                         Set blocks not sent to far players
2393                                 */
2394                                 for(core::list<u16>::Iterator
2395                                                 i = far_players.begin();
2396                                                 i != far_players.end(); i++)
2397                                 {
2398                                         u16 peer_id = *i;
2399                                         RemoteClient *client = getClient(peer_id);
2400                                         if(client==NULL)
2401                                                 continue;
2402                                         client->SetBlocksNotSent(modified_blocks);
2403                                 }
2404
2405                                 /*
2406                                         Calculate special events
2407                                 */
2408                                 
2409                                 /*if(n.d == CONTENT_MESE)
2410                                 {
2411                                         u32 count = 0;
2412                                         for(s16 z=-1; z<=1; z++)
2413                                         for(s16 y=-1; y<=1; y++)
2414                                         for(s16 x=-1; x<=1; x++)
2415                                         {
2416                                                 
2417                                         }
2418                                 }*/
2419                         }
2420                         /*
2421                                 Place other item (not a block)
2422                         */
2423                         else
2424                         {
2425                                 v3s16 blockpos = getNodeBlockPos(p_over);
2426                                 
2427                                 /*
2428                                         Check that the block is loaded so that the item
2429                                         can properly be added to the static list too
2430                                 */
2431                                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2432                                 if(block==NULL)
2433                                 {
2434                                         derr_server<<"Error while placing object: "
2435                                                         "block not found"<<std::endl;
2436                                         return;
2437                                 }
2438
2439                                 v3f pos = intToFloat(p_over, BS);
2440                                 pos.Y -= BS*0.45;
2441
2442                                 dout_server<<"Placing a miscellaneous item on map"
2443                                                 <<std::endl;
2444                                                 
2445                                 /*
2446                                         Create an ItemSAO
2447                                 */
2448                                 // Get item string
2449                                 std::ostringstream os(std::ios_base::binary);
2450                                 item->serialize(os);
2451                                 dout_server<<"Item string is \""<<os.str()<<"\""<<std::endl;
2452                                 // Create object
2453                                 ServerActiveObject *obj = new ItemSAO
2454                                                 (&m_env, 0, pos, os.str());
2455
2456                                 if(obj == NULL)
2457                                 {
2458                                         derr_server<<"WARNING: item resulted in NULL object, "
2459                                                         <<"not placing onto map"
2460                                                         <<std::endl;
2461                                 }
2462                                 else
2463                                 {
2464                                         // Add the object to the environment
2465                                         m_env.addActiveObject(obj);
2466                                         
2467                                         dout_server<<"Placed object"<<std::endl;
2468
2469                                         InventoryList *ilist = player->inventory.getList("main");
2470                                         if(g_settings.getBool("creative_mode") == false && ilist)
2471                                         {
2472                                                 // Remove from inventory and send inventory
2473                                                 ilist->deleteItem(item_i);
2474                                                 // Send inventory
2475                                                 SendInventory(peer_id);
2476                                         }
2477                                 }
2478                         }
2479
2480                 } // action == 1
2481
2482                 /*
2483                         Catch invalid actions
2484                 */
2485                 else
2486                 {
2487                         derr_server<<"WARNING: Server: Invalid action "
2488                                         <<action<<std::endl;
2489                 }
2490         }
2491 #if 0
2492         else if(command == TOSERVER_RELEASE)
2493         {
2494                 if(datasize < 3)
2495                         return;
2496                 /*
2497                         length: 3
2498                         [0] u16 command
2499                         [2] u8 button
2500                 */
2501                 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
2502         }
2503 #endif
2504         else if(command == TOSERVER_SIGNTEXT)
2505         {
2506                 /*
2507                         u16 command
2508                         v3s16 blockpos
2509                         s16 id
2510                         u16 textlen
2511                         textdata
2512                 */
2513                 std::string datastring((char*)&data[2], datasize-2);
2514                 std::istringstream is(datastring, std::ios_base::binary);
2515                 u8 buf[6];
2516                 // Read stuff
2517                 is.read((char*)buf, 6);
2518                 v3s16 blockpos = readV3S16(buf);
2519                 is.read((char*)buf, 2);
2520                 s16 id = readS16(buf);
2521                 is.read((char*)buf, 2);
2522                 u16 textlen = readU16(buf);
2523                 std::string text;
2524                 for(u16 i=0; i<textlen; i++)
2525                 {
2526                         is.read((char*)buf, 1);
2527                         text += (char)buf[0];
2528                 }
2529
2530                 MapBlock *block = NULL;
2531                 try
2532                 {
2533                         block = m_env.getMap().getBlockNoCreate(blockpos);
2534                 }
2535                 catch(InvalidPositionException &e)
2536                 {
2537                         derr_server<<"Error while setting sign text: "
2538                                         "block not found"<<std::endl;
2539                         return;
2540                 }
2541
2542                 MapBlockObject *obj = block->getObject(id);
2543                 if(obj == NULL)
2544                 {
2545                         derr_server<<"Error while setting sign text: "
2546                                         "object not found"<<std::endl;
2547                         return;
2548                 }
2549                 
2550                 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
2551                 {
2552                         derr_server<<"Error while setting sign text: "
2553                                         "object is not a sign"<<std::endl;
2554                         return;
2555                 }
2556
2557                 ((SignObject*)obj)->setText(text);
2558
2559                 obj->getBlock()->setChangedFlag();
2560         }
2561         else if(command == TOSERVER_SIGNNODETEXT)
2562         {
2563                 /*
2564                         u16 command
2565                         v3s16 p
2566                         u16 textlen
2567                         textdata
2568                 */
2569                 std::string datastring((char*)&data[2], datasize-2);
2570                 std::istringstream is(datastring, std::ios_base::binary);
2571                 u8 buf[6];
2572                 // Read stuff
2573                 is.read((char*)buf, 6);
2574                 v3s16 p = readV3S16(buf);
2575                 is.read((char*)buf, 2);
2576                 u16 textlen = readU16(buf);
2577                 std::string text;
2578                 for(u16 i=0; i<textlen; i++)
2579                 {
2580                         is.read((char*)buf, 1);
2581                         text += (char)buf[0];
2582                 }
2583
2584                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
2585                 if(!meta)
2586                         return;
2587                 if(meta->typeId() != CONTENT_SIGN_WALL)
2588                         return;
2589                 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
2590                 signmeta->setText(text);
2591                 
2592                 v3s16 blockpos = getNodeBlockPos(p);
2593                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2594                 if(block)
2595                 {
2596                         block->setChangedFlag();
2597                 }
2598
2599                 for(core::map<u16, RemoteClient*>::Iterator
2600                         i = m_clients.getIterator();
2601                         i.atEnd()==false; i++)
2602                 {
2603                         RemoteClient *client = i.getNode()->getValue();
2604                         client->SetBlockNotSent(blockpos);
2605                 }
2606         }
2607         else if(command == TOSERVER_INVENTORY_ACTION)
2608         {
2609                 /*// Ignore inventory changes if in creative mode
2610                 if(g_settings.getBool("creative_mode") == true)
2611                 {
2612                         dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
2613                                         <<std::endl;
2614                         return;
2615                 }*/
2616                 // Strip command and create a stream
2617                 std::string datastring((char*)&data[2], datasize-2);
2618                 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2619                 std::istringstream is(datastring, std::ios_base::binary);
2620                 // Create an action
2621                 InventoryAction *a = InventoryAction::deSerialize(is);
2622                 if(a != NULL)
2623                 {
2624                         // Create context
2625                         InventoryContext c;
2626                         c.current_player = player;
2627
2628                         /*
2629                                 Handle craftresult specially if not in creative mode
2630                         */
2631                         bool disable_action = false;
2632                         if(a->getType() == IACTION_MOVE
2633                                         && g_settings.getBool("creative_mode") == false)
2634                         {
2635                                 IMoveAction *ma = (IMoveAction*)a;
2636                                 if(ma->to_inv == "current_player" &&
2637                                                 ma->from_inv == "current_player")
2638                                 {
2639                                         // Don't allow moving anything to craftresult
2640                                         if(ma->to_list == "craftresult")
2641                                         {
2642                                                 // Do nothing
2643                                                 disable_action = true;
2644                                         }
2645                                         // When something is removed from craftresult
2646                                         if(ma->from_list == "craftresult")
2647                                         {
2648                                                 disable_action = true;
2649                                                 // Remove stuff from craft
2650                                                 InventoryList *clist = player->inventory.getList("craft");
2651                                                 if(clist)
2652                                                 {
2653                                                         u16 count = ma->count;
2654                                                         if(count == 0)
2655                                                                 count = 1;
2656                                                         clist->decrementMaterials(count);
2657                                                 }
2658                                                 // Do action
2659                                                 // Feed action to player inventory
2660                                                 //a->apply(&player->inventory);
2661                                                 a->apply(&c, this);
2662                                                 // Eat it
2663                                                 delete a;
2664                                                 // If something appeared in craftresult, throw it
2665                                                 // in the main list
2666                                                 InventoryList *rlist = player->inventory.getList("craftresult");
2667                                                 InventoryList *mlist = player->inventory.getList("main");
2668                                                 if(rlist && mlist && rlist->getUsedSlots() == 1)
2669                                                 {
2670                                                         InventoryItem *item1 = rlist->changeItem(0, NULL);
2671                                                         mlist->addItem(item1);
2672                                                 }
2673                                         }
2674                                 }
2675                         }
2676                         
2677                         if(disable_action == false)
2678                         {
2679                                 // Feed action to player inventory
2680                                 //a->apply(&player->inventory);
2681                                 a->apply(&c, this);
2682                                 // Eat the action
2683                                 delete a;
2684                         }
2685                         else
2686                         {
2687                                 // Send inventory
2688                                 SendInventory(player->peer_id);
2689                         }
2690                 }
2691                 else
2692                 {
2693                         dstream<<"TOSERVER_INVENTORY_ACTION: "
2694                                         <<"InventoryAction::deSerialize() returned NULL"
2695                                         <<std::endl;
2696                 }
2697         }
2698         else if(command == TOSERVER_CHAT_MESSAGE)
2699         {
2700                 /*
2701                         u16 command
2702                         u16 length
2703                         wstring message
2704                 */
2705                 u8 buf[6];
2706                 std::string datastring((char*)&data[2], datasize-2);
2707                 std::istringstream is(datastring, std::ios_base::binary);
2708                 
2709                 // Read stuff
2710                 is.read((char*)buf, 2);
2711                 u16 len = readU16(buf);
2712                 
2713                 std::wstring message;
2714                 for(u16 i=0; i<len; i++)
2715                 {
2716                         is.read((char*)buf, 2);
2717                         message += (wchar_t)readU16(buf);
2718                 }
2719
2720                 // Get player name of this client
2721                 std::wstring name = narrow_to_wide(player->getName());
2722                 
2723                 // Line to send to players
2724                 std::wstring line;
2725                 // Whether to send to the player that sent the line
2726                 bool send_to_sender = false;
2727                 // Whether to send to other players
2728                 bool send_to_others = false;
2729                 
2730                 // Parse commands
2731                 std::wstring commandprefix = L"/#";
2732                 if(message.substr(0, commandprefix.size()) == commandprefix)
2733                 {
2734                         line += L"Server: ";
2735
2736                         message = message.substr(commandprefix.size());
2737                         // Get player name as narrow string
2738                         std::string name_s = player->getName();
2739                         // Convert message to narrow string
2740                         std::string message_s = wide_to_narrow(message);
2741                         // Operator is the single name defined in config.
2742                         std::string operator_name = g_settings.get("name");
2743                         bool is_operator = (operator_name != "" &&
2744                                         wide_to_narrow(name) == operator_name);
2745                         bool valid_command = false;
2746                         if(message_s == "help")
2747                         {
2748                                 line += L"-!- Available commands: ";
2749                                 line += L"status ";
2750                                 if(is_operator)
2751                                 {
2752                                         line += L"shutdown setting ";
2753                                 }
2754                                 else
2755                                 {
2756                                 }
2757                                 send_to_sender = true;
2758                                 valid_command = true;
2759                         }
2760                         else if(message_s == "status")
2761                         {
2762                                 line = getStatusString();
2763                                 send_to_sender = true;
2764                                 valid_command = true;
2765                         }
2766                         else if(is_operator)
2767                         {
2768                                 if(message_s == "shutdown")
2769                                 {
2770                                         dstream<<DTIME<<" Server: Operator requested shutdown."
2771                                                         <<std::endl;
2772                                         m_shutdown_requested.set(true);
2773                                         
2774                                         line += L"*** Server shutting down (operator request)";
2775                                         send_to_sender = true;
2776                                         valid_command = true;
2777                                 }
2778                                 else if(message_s.substr(0,8) == "setting ")
2779                                 {
2780                                         std::string confline = message_s.substr(8);
2781                                         g_settings.parseConfigLine(confline);
2782                                         line += L"-!- Setting changed.";
2783                                         send_to_sender = true;
2784                                         valid_command = true;
2785                                 }
2786                         }
2787                         
2788                         if(valid_command == false)
2789                         {
2790                                 line += L"-!- Invalid command: " + message;
2791                                 send_to_sender = true;
2792                         }
2793                 }
2794                 else
2795                 {
2796                         line += L"<";
2797                         /*if(is_operator)
2798                                 line += L"@";*/
2799                         line += name;
2800                         line += L"> ";
2801                         line += message;
2802                         send_to_others = true;
2803                 }
2804                 
2805                 if(line != L"")
2806                 {
2807                         dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2808
2809                         /*
2810                                 Send the message to clients
2811                         */
2812                         for(core::map<u16, RemoteClient*>::Iterator
2813                                 i = m_clients.getIterator();
2814                                 i.atEnd() == false; i++)
2815                         {
2816                                 // Get client and check that it is valid
2817                                 RemoteClient *client = i.getNode()->getValue();
2818                                 assert(client->peer_id == i.getNode()->getKey());
2819                                 if(client->serialization_version == SER_FMT_VER_INVALID)
2820                                         continue;
2821
2822                                 // Filter recipient
2823                                 bool sender_selected = (peer_id == client->peer_id);
2824                                 if(sender_selected == true && send_to_sender == false)
2825                                         continue;
2826                                 if(sender_selected == false && send_to_others == false)
2827                                         continue;
2828
2829                                 SendChatMessage(client->peer_id, line);
2830                         }
2831                 }
2832         }
2833         else
2834         {
2835                 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
2836                                 "unknown command "<<command<<std::endl;
2837         }
2838         
2839         } //try
2840         catch(SendFailedException &e)
2841         {
2842                 derr_server<<"Server::ProcessData(): SendFailedException: "
2843                                 <<"what="<<e.what()
2844                                 <<std::endl;
2845         }
2846 }
2847
2848 void Server::onMapEditEvent(MapEditEvent *event)
2849 {
2850         dstream<<"Server::onMapEditEvent()"<<std::endl;
2851         if(m_ignore_map_edit_events)
2852                 return;
2853         MapEditEvent *e = event->clone();
2854         m_unsent_map_edit_queue.push_back(e);
2855 }
2856
2857 Inventory* Server::getInventory(InventoryContext *c, std::string id)
2858 {
2859         if(id == "current_player")
2860         {
2861                 assert(c->current_player);
2862                 return &(c->current_player->inventory);
2863         }
2864         
2865         Strfnd fn(id);
2866         std::string id0 = fn.next(":");
2867
2868         if(id0 == "nodemeta")
2869         {
2870                 v3s16 p;
2871                 p.X = stoi(fn.next(","));
2872                 p.Y = stoi(fn.next(","));
2873                 p.Z = stoi(fn.next(","));
2874                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
2875                 if(meta)
2876                         return meta->getInventory();
2877                 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
2878                                 <<"no metadata found"<<std::endl;
2879                 return NULL;
2880         }
2881
2882         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
2883         return NULL;
2884 }
2885 void Server::inventoryModified(InventoryContext *c, std::string id)
2886 {
2887         if(id == "current_player")
2888         {
2889                 assert(c->current_player);
2890                 // Send inventory
2891                 SendInventory(c->current_player->peer_id);
2892                 return;
2893         }
2894         
2895         Strfnd fn(id);
2896         std::string id0 = fn.next(":");
2897
2898         if(id0 == "nodemeta")
2899         {
2900                 v3s16 p;
2901                 p.X = stoi(fn.next(","));
2902                 p.Y = stoi(fn.next(","));
2903                 p.Z = stoi(fn.next(","));
2904                 v3s16 blockpos = getNodeBlockPos(p);
2905
2906                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
2907                 if(meta)
2908                         meta->inventoryModified();
2909
2910                 for(core::map<u16, RemoteClient*>::Iterator
2911                         i = m_clients.getIterator();
2912                         i.atEnd()==false; i++)
2913                 {
2914                         RemoteClient *client = i.getNode()->getValue();
2915                         client->SetBlockNotSent(blockpos);
2916                 }
2917
2918                 return;
2919         }
2920
2921         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
2922 }
2923
2924 core::list<PlayerInfo> Server::getPlayerInfo()
2925 {
2926         DSTACK(__FUNCTION_NAME);
2927         JMutexAutoLock envlock(m_env_mutex);
2928         JMutexAutoLock conlock(m_con_mutex);
2929         
2930         core::list<PlayerInfo> list;
2931
2932         core::list<Player*> players = m_env.getPlayers();
2933         
2934         core::list<Player*>::Iterator i;
2935         for(i = players.begin();
2936                         i != players.end(); i++)
2937         {
2938                 PlayerInfo info;
2939
2940                 Player *player = *i;
2941
2942                 try{
2943                         con::Peer *peer = m_con.GetPeer(player->peer_id);
2944                         // Copy info from peer to info struct
2945                         info.id = peer->id;
2946                         info.address = peer->address;
2947                         info.avg_rtt = peer->avg_rtt;
2948                 }
2949                 catch(con::PeerNotFoundException &e)
2950                 {
2951                         // Set dummy peer info
2952                         info.id = 0;
2953                         info.address = Address(0,0,0,0,0);
2954                         info.avg_rtt = 0.0;
2955                 }
2956
2957                 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
2958                 info.position = player->getPosition();
2959
2960                 list.push_back(info);
2961         }
2962
2963         return list;
2964 }
2965
2966
2967 void Server::peerAdded(con::Peer *peer)
2968 {
2969         DSTACK(__FUNCTION_NAME);
2970         dout_server<<"Server::peerAdded(): peer->id="
2971                         <<peer->id<<std::endl;
2972         
2973         PeerChange c;
2974         c.type = PEER_ADDED;
2975         c.peer_id = peer->id;
2976         c.timeout = false;
2977         m_peer_change_queue.push_back(c);
2978 }
2979
2980 void Server::deletingPeer(con::Peer *peer, bool timeout)
2981 {
2982         DSTACK(__FUNCTION_NAME);
2983         dout_server<<"Server::deletingPeer(): peer->id="
2984                         <<peer->id<<", timeout="<<timeout<<std::endl;
2985         
2986         PeerChange c;
2987         c.type = PEER_REMOVED;
2988         c.peer_id = peer->id;
2989         c.timeout = timeout;
2990         m_peer_change_queue.push_back(c);
2991 }
2992
2993 void Server::SendObjectData(float dtime)
2994 {
2995         DSTACK(__FUNCTION_NAME);
2996
2997         core::map<v3s16, bool> stepped_blocks;
2998         
2999         for(core::map<u16, RemoteClient*>::Iterator
3000                 i = m_clients.getIterator();
3001                 i.atEnd() == false; i++)
3002         {
3003                 u16 peer_id = i.getNode()->getKey();
3004                 RemoteClient *client = i.getNode()->getValue();
3005                 assert(client->peer_id == peer_id);
3006                 
3007                 if(client->serialization_version == SER_FMT_VER_INVALID)
3008                         continue;
3009                 
3010                 client->SendObjectData(this, dtime, stepped_blocks);
3011         }
3012 }
3013
3014 void Server::SendPlayerInfos()
3015 {
3016         DSTACK(__FUNCTION_NAME);
3017
3018         //JMutexAutoLock envlock(m_env_mutex);
3019         
3020         // Get connected players
3021         core::list<Player*> players = m_env.getPlayers(true);
3022         
3023         u32 player_count = players.getSize();
3024         u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3025
3026         SharedBuffer<u8> data(datasize);
3027         writeU16(&data[0], TOCLIENT_PLAYERINFO);
3028         
3029         u32 start = 2;
3030         core::list<Player*>::Iterator i;
3031         for(i = players.begin();
3032                         i != players.end(); i++)
3033         {
3034                 Player *player = *i;
3035
3036                 /*dstream<<"Server sending player info for player with "
3037                                 "peer_id="<<player->peer_id<<std::endl;*/
3038                 
3039                 writeU16(&data[start], player->peer_id);
3040                 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3041                 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3042                 start += 2+PLAYERNAME_SIZE;
3043         }
3044
3045         //JMutexAutoLock conlock(m_con_mutex);
3046
3047         // Send as reliable
3048         m_con.SendToAll(0, data, true);
3049 }
3050
3051 void Server::SendInventory(u16 peer_id)
3052 {
3053         DSTACK(__FUNCTION_NAME);
3054         
3055         Player* player = m_env.getPlayer(peer_id);
3056
3057         /*
3058                 Calculate crafting stuff
3059         */
3060         if(g_settings.getBool("creative_mode") == false)
3061         {
3062                 InventoryList *clist = player->inventory.getList("craft");
3063                 InventoryList *rlist = player->inventory.getList("craftresult");
3064                 if(rlist)
3065                 {
3066                         rlist->clearItems();
3067                 }
3068                 if(clist && rlist)
3069                 {
3070                         InventoryItem *items[9];
3071                         for(u16 i=0; i<9; i++)
3072                         {
3073                                 items[i] = clist->getItem(i);
3074                         }
3075                         
3076                         bool found = false;
3077
3078                         // Wood
3079                         if(!found)
3080                         {
3081                                 ItemSpec specs[9];
3082                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_TREE);
3083                                 if(checkItemCombination(items, specs))
3084                                 {
3085                                         rlist->addItem(new MaterialItem(CONTENT_WOOD, 4));
3086                                         found = true;
3087                                 }
3088                         }
3089
3090                         // Stick
3091                         if(!found)
3092                         {
3093                                 ItemSpec specs[9];
3094                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3095                                 if(checkItemCombination(items, specs))
3096                                 {
3097                                         rlist->addItem(new CraftItem("Stick", 4));
3098                                         found = true;
3099                                 }
3100                         }
3101
3102                         // Sign
3103                         if(!found)
3104                         {
3105                                 ItemSpec specs[9];
3106                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3107                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3108                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3109                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3110                                 specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3111                                 specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3112                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3113                                 if(checkItemCombination(items, specs))
3114                                 {
3115                                         //rlist->addItem(new MapBlockObjectItem("Sign"));
3116                                         rlist->addItem(new MaterialItem(CONTENT_SIGN_WALL, 1));
3117                                         found = true;
3118                                 }
3119                         }
3120
3121                         // Torch
3122                         if(!found)
3123                         {
3124                                 ItemSpec specs[9];
3125                                 specs[0] = ItemSpec(ITEM_CRAFT, "lump_of_coal");
3126                                 specs[3] = ItemSpec(ITEM_CRAFT, "Stick");
3127                                 if(checkItemCombination(items, specs))
3128                                 {
3129                                         rlist->addItem(new MaterialItem(CONTENT_TORCH, 4));
3130                                         found = true;
3131                                 }
3132                         }
3133
3134                         // Wooden pick
3135                         if(!found)
3136                         {
3137                                 ItemSpec specs[9];
3138                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3139                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3140                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3141                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3142                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3143                                 if(checkItemCombination(items, specs))
3144                                 {
3145                                         rlist->addItem(new ToolItem("WPick", 0));
3146                                         found = true;
3147                                 }
3148                         }
3149
3150                         // Stone pick
3151                         if(!found)
3152                         {
3153                                 ItemSpec specs[9];
3154                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3155                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3156                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3157                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3158                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3159                                 if(checkItemCombination(items, specs))
3160                                 {
3161                                         rlist->addItem(new ToolItem("STPick", 0));
3162                                         found = true;
3163                                 }
3164                         }
3165
3166                         // Steel pick
3167                         if(!found)
3168                         {
3169                                 ItemSpec specs[9];
3170                                 specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3171                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3172                                 specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3173                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3174                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3175                                 if(checkItemCombination(items, specs))
3176                                 {
3177                                         rlist->addItem(new ToolItem("SteelPick", 0));
3178                                         found = true;
3179                                 }
3180                         }
3181
3182                         // Mese pick
3183                         if(!found)
3184                         {
3185                                 ItemSpec specs[9];
3186                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
3187                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
3188                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_MESE);
3189                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3190                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3191                                 if(checkItemCombination(items, specs))
3192                                 {
3193                                         rlist->addItem(new ToolItem("MesePick", 0));
3194                                         found = true;
3195                                 }
3196                         }
3197
3198                         // Wooden showel
3199                         if(!found)
3200                         {
3201                                 ItemSpec specs[9];
3202                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3203                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3204                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3205                                 if(checkItemCombination(items, specs))
3206                                 {
3207                                         rlist->addItem(new ToolItem("WShovel", 0));
3208                                         found = true;
3209                                 }
3210                         }
3211
3212                         // Stone showel
3213                         if(!found)
3214                         {
3215                                 ItemSpec specs[9];
3216                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3217                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3218                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3219                                 if(checkItemCombination(items, specs))
3220                                 {
3221                                         rlist->addItem(new ToolItem("STShovel", 0));
3222                                         found = true;
3223                                 }
3224                         }
3225
3226                         // Steel showel
3227                         if(!found)
3228                         {
3229                                 ItemSpec specs[9];
3230                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3231                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3232                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3233                                 if(checkItemCombination(items, specs))
3234                                 {
3235                                         rlist->addItem(new ToolItem("SteelShovel", 0));
3236                                         found = true;
3237                                 }
3238                         }
3239
3240                         // Wooden axe
3241                         if(!found)
3242                         {
3243                                 ItemSpec specs[9];
3244                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3245                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3246                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3247                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3248                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3249                                 if(checkItemCombination(items, specs))
3250                                 {
3251                                         rlist->addItem(new ToolItem("WAxe", 0));
3252                                         found = true;
3253                                 }
3254                         }
3255
3256                         // Stone axe
3257                         if(!found)
3258                         {
3259                                 ItemSpec specs[9];
3260                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3261                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3262                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3263                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3264                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3265                                 if(checkItemCombination(items, specs))
3266                                 {
3267                                         rlist->addItem(new ToolItem("STAxe", 0));
3268                                         found = true;
3269                                 }
3270                         }
3271
3272                         // Steel axe
3273                         if(!found)
3274                         {
3275                                 ItemSpec specs[9];
3276                                 specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3277                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3278                                 specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3279                                 specs[4] = ItemSpec(ITEM_CRAFT, "Stick");
3280                                 specs[7] = ItemSpec(ITEM_CRAFT, "Stick");
3281                                 if(checkItemCombination(items, specs))
3282                                 {
3283                                         rlist->addItem(new ToolItem("SteelAxe", 0));
3284                                         found = true;
3285                                 }
3286                         }
3287
3288                         // Chest
3289                         if(!found)
3290                         {
3291                                 ItemSpec specs[9];
3292                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3293                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3294                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3295                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3296                                 specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3297                                 specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3298                                 specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3299                                 specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD);
3300                                 if(checkItemCombination(items, specs))
3301                                 {
3302                                         rlist->addItem(new MaterialItem(CONTENT_CHEST, 1));
3303                                         found = true;
3304                                 }
3305                         }
3306
3307                         // Furnace
3308                         if(!found)
3309                         {
3310                                 ItemSpec specs[9];
3311                                 specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3312                                 specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3313                                 specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3314                                 specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3315                                 specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3316                                 specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3317                                 specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3318                                 specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_COBBLE);
3319                                 if(checkItemCombination(items, specs))
3320                                 {
3321                                         rlist->addItem(new MaterialItem(CONTENT_FURNACE, 1));
3322                                         found = true;
3323                                 }
3324                         }
3325
3326                         // Steel block
3327                         if(!found)
3328                         {
3329                                 ItemSpec specs[9];
3330                                 specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3331                                 specs[1] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3332                                 specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3333                                 specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3334                                 specs[4] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3335                                 specs[5] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3336                                 specs[6] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3337                                 specs[7] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3338                                 specs[8] = ItemSpec(ITEM_CRAFT, "steel_ingot");
3339                                 if(checkItemCombination(items, specs))
3340                                 {
3341                                         rlist->addItem(new MaterialItem(CONTENT_STEEL, 1));
3342                                         found = true;
3343                                 }
3344                         }
3345
3346                 }
3347         } // if creative_mode == false
3348
3349         /*
3350                 Serialize it
3351         */
3352
3353         std::ostringstream os;
3354         //os.imbue(std::locale("C"));
3355
3356         player->inventory.serialize(os);
3357
3358         std::string s = os.str();
3359         
3360         SharedBuffer<u8> data(s.size()+2);
3361         writeU16(&data[0], TOCLIENT_INVENTORY);
3362         memcpy(&data[2], s.c_str(), s.size());
3363         
3364         // Send as reliable
3365         m_con.Send(peer_id, 0, data, true);
3366 }
3367
3368 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3369 {
3370         DSTACK(__FUNCTION_NAME);
3371         
3372         std::ostringstream os(std::ios_base::binary);
3373         u8 buf[12];
3374         
3375         // Write command
3376         writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3377         os.write((char*)buf, 2);
3378         
3379         // Write length
3380         writeU16(buf, message.size());
3381         os.write((char*)buf, 2);
3382         
3383         // Write string
3384         for(u32 i=0; i<message.size(); i++)
3385         {
3386                 u16 w = message[i];
3387                 writeU16(buf, w);
3388                 os.write((char*)buf, 2);
3389         }
3390         
3391         // Make data buffer
3392         std::string s = os.str();
3393         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3394         // Send as reliable
3395         m_con.Send(peer_id, 0, data, true);
3396 }
3397
3398 void Server::BroadcastChatMessage(const std::wstring &message)
3399 {
3400         for(core::map<u16, RemoteClient*>::Iterator
3401                 i = m_clients.getIterator();
3402                 i.atEnd() == false; i++)
3403         {
3404                 // Get client and check that it is valid
3405                 RemoteClient *client = i.getNode()->getValue();
3406                 assert(client->peer_id == i.getNode()->getKey());
3407                 if(client->serialization_version == SER_FMT_VER_INVALID)
3408                         continue;
3409
3410                 SendChatMessage(client->peer_id, message);
3411         }
3412 }
3413
3414 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3415         core::list<u16> *far_players, float far_d_nodes)
3416 {
3417         float maxd = far_d_nodes*BS;
3418         v3f p_f = intToFloat(p, BS);
3419
3420         // Create packet
3421         u32 replysize = 8;
3422         SharedBuffer<u8> reply(replysize);
3423         writeU16(&reply[0], TOCLIENT_REMOVENODE);
3424         writeS16(&reply[2], p.X);
3425         writeS16(&reply[4], p.Y);
3426         writeS16(&reply[6], p.Z);
3427
3428         for(core::map<u16, RemoteClient*>::Iterator
3429                 i = m_clients.getIterator();
3430                 i.atEnd() == false; i++)
3431         {
3432                 // Get client and check that it is valid
3433                 RemoteClient *client = i.getNode()->getValue();
3434                 assert(client->peer_id == i.getNode()->getKey());
3435                 if(client->serialization_version == SER_FMT_VER_INVALID)
3436                         continue;
3437
3438                 // Don't send if it's the same one
3439                 if(client->peer_id == ignore_id)
3440                         continue;
3441                 
3442                 if(far_players)
3443                 {
3444                         // Get player
3445                         Player *player = m_env.getPlayer(client->peer_id);
3446                         if(player)
3447                         {
3448                                 // If player is far away, only set modified blocks not sent
3449                                 v3f player_pos = player->getPosition();
3450                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3451                                 {
3452                                         far_players->push_back(client->peer_id);
3453                                         continue;
3454                                 }
3455                         }
3456                 }
3457
3458                 // Send as reliable
3459                 m_con.Send(client->peer_id, 0, reply, true);
3460         }
3461 }
3462
3463 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3464                 core::list<u16> *far_players, float far_d_nodes)
3465 {
3466         float maxd = far_d_nodes*BS;
3467         v3f p_f = intToFloat(p, BS);
3468
3469         for(core::map<u16, RemoteClient*>::Iterator
3470                 i = m_clients.getIterator();
3471                 i.atEnd() == false; i++)
3472         {
3473                 // Get client and check that it is valid
3474                 RemoteClient *client = i.getNode()->getValue();
3475                 assert(client->peer_id == i.getNode()->getKey());
3476                 if(client->serialization_version == SER_FMT_VER_INVALID)
3477                         continue;
3478
3479                 // Don't send if it's the same one
3480                 if(client->peer_id == ignore_id)
3481                         continue;
3482
3483                 if(far_players)
3484                 {
3485                         // Get player
3486                         Player *player = m_env.getPlayer(client->peer_id);
3487                         if(player)
3488                         {
3489                                 // If player is far away, only set modified blocks not sent
3490                                 v3f player_pos = player->getPosition();
3491                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3492                                 {
3493                                         far_players->push_back(client->peer_id);
3494                                         continue;
3495                                 }
3496                         }
3497                 }
3498
3499                 // Create packet
3500                 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3501                 SharedBuffer<u8> reply(replysize);
3502                 writeU16(&reply[0], TOCLIENT_ADDNODE);
3503                 writeS16(&reply[2], p.X);
3504                 writeS16(&reply[4], p.Y);
3505                 writeS16(&reply[6], p.Z);
3506                 n.serialize(&reply[8], client->serialization_version);
3507
3508                 // Send as reliable
3509                 m_con.Send(client->peer_id, 0, reply, true);
3510         }
3511 }
3512
3513 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3514 {
3515         DSTACK(__FUNCTION_NAME);
3516         /*
3517                 Create a packet with the block in the right format
3518         */
3519         
3520         std::ostringstream os(std::ios_base::binary);
3521         block->serialize(os, ver);
3522         std::string s = os.str();
3523         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3524
3525         u32 replysize = 8 + blockdata.getSize();
3526         SharedBuffer<u8> reply(replysize);
3527         v3s16 p = block->getPos();
3528         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3529         writeS16(&reply[2], p.X);
3530         writeS16(&reply[4], p.Y);
3531         writeS16(&reply[6], p.Z);
3532         memcpy(&reply[8], *blockdata, blockdata.getSize());
3533
3534         /*dstream<<"Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3535                         <<":  \tpacket size: "<<replysize<<std::endl;*/
3536         
3537         /*
3538                 Send packet
3539         */
3540         m_con.Send(peer_id, 1, reply, true);
3541 }
3542
3543 void Server::SendBlocks(float dtime)
3544 {
3545         DSTACK(__FUNCTION_NAME);
3546
3547         JMutexAutoLock envlock(m_env_mutex);
3548         JMutexAutoLock conlock(m_con_mutex);
3549
3550         //TimeTaker timer("Server::SendBlocks");
3551
3552         core::array<PrioritySortedBlockTransfer> queue;
3553
3554         s32 total_sending = 0;
3555
3556         for(core::map<u16, RemoteClient*>::Iterator
3557                 i = m_clients.getIterator();
3558                 i.atEnd() == false; i++)
3559         {
3560                 RemoteClient *client = i.getNode()->getValue();
3561                 assert(client->peer_id == i.getNode()->getKey());
3562
3563                 total_sending += client->SendingCount();
3564                 
3565                 if(client->serialization_version == SER_FMT_VER_INVALID)
3566                         continue;
3567                 
3568                 client->GetNextBlocks(this, dtime, queue);
3569         }
3570
3571         // Sort.
3572         // Lowest priority number comes first.
3573         // Lowest is most important.
3574         queue.sort();
3575
3576         for(u32 i=0; i<queue.size(); i++)
3577         {
3578                 //TODO: Calculate limit dynamically
3579                 if(total_sending >= g_settings.getS32
3580                                 ("max_simultaneous_block_sends_server_total"))
3581                         break;
3582                 
3583                 PrioritySortedBlockTransfer q = queue[i];
3584
3585                 MapBlock *block = NULL;
3586                 try
3587                 {
3588                         block = m_env.getMap().getBlockNoCreate(q.pos);
3589                 }
3590                 catch(InvalidPositionException &e)
3591                 {
3592                         continue;
3593                 }
3594
3595                 RemoteClient *client = getClient(q.peer_id);
3596
3597                 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3598
3599                 client->SentBlock(q.pos);
3600
3601                 total_sending++;
3602         }
3603 }
3604
3605
3606 RemoteClient* Server::getClient(u16 peer_id)
3607 {
3608         DSTACK(__FUNCTION_NAME);
3609         //JMutexAutoLock lock(m_con_mutex);
3610         core::map<u16, RemoteClient*>::Node *n;
3611         n = m_clients.find(peer_id);
3612         // A client should exist for all peers
3613         assert(n != NULL);
3614         return n->getValue();
3615 }
3616
3617 std::wstring Server::getStatusString()
3618 {
3619         std::wostringstream os(std::ios_base::binary);
3620         os<<L"# Server: ";
3621         // Uptime
3622         os<<L"uptime="<<m_uptime.get();
3623         // Information about clients
3624         os<<L", clients={";
3625         for(core::map<u16, RemoteClient*>::Iterator
3626                 i = m_clients.getIterator();
3627                 i.atEnd() == false; i++)
3628         {
3629                 // Get client and check that it is valid
3630                 RemoteClient *client = i.getNode()->getValue();
3631                 assert(client->peer_id == i.getNode()->getKey());
3632                 if(client->serialization_version == SER_FMT_VER_INVALID)
3633                         continue;
3634                 // Get player
3635                 Player *player = m_env.getPlayer(client->peer_id);
3636                 // Get name of player
3637                 std::wstring name = L"unknown";
3638                 if(player != NULL)
3639                         name = narrow_to_wide(player->getName());
3640                 // Add name to information string
3641                 os<<name<<L",";
3642         }
3643         os<<L"}";
3644         if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
3645                 os<<" WARNING: Map saving is disabled."<<std::endl;
3646         return os.str();
3647 }
3648
3649
3650 void setCreativeInventory(Player *player)
3651 {
3652         player->resetInventory();
3653         
3654         // Give some good picks
3655         {
3656                 InventoryItem *item = new ToolItem("STPick", 0);
3657                 void* r = player->inventory.addItem("main", item);
3658                 assert(r == NULL);
3659         }
3660         {
3661                 InventoryItem *item = new ToolItem("MesePick", 0);
3662                 void* r = player->inventory.addItem("main", item);
3663                 assert(r == NULL);
3664         }
3665
3666         /*
3667                 Give materials
3668         */
3669         
3670         // CONTENT_IGNORE-terminated list
3671         u8 material_items[] = {
3672                 CONTENT_TORCH,
3673                 CONTENT_COBBLE,
3674                 CONTENT_MUD,
3675                 CONTENT_STONE,
3676                 CONTENT_SAND,
3677                 CONTENT_TREE,
3678                 CONTENT_LEAVES,
3679                 CONTENT_MESE,
3680                 CONTENT_WATERSOURCE,
3681                 CONTENT_CLOUD,
3682                 CONTENT_CHEST,
3683                 CONTENT_FURNACE,
3684                 CONTENT_SIGN_WALL,
3685                 CONTENT_IGNORE
3686         };
3687         
3688         u8 *mip = material_items;
3689         for(u16 i=0; i<PLAYER_INVENTORY_SIZE; i++)
3690         {
3691                 if(*mip == CONTENT_IGNORE)
3692                         break;
3693
3694                 InventoryItem *item = new MaterialItem(*mip, 1);
3695                 player->inventory.addItem("main", item);
3696
3697                 mip++;
3698         }
3699
3700 #if 0
3701         assert(USEFUL_CONTENT_COUNT <= PLAYER_INVENTORY_SIZE);
3702         
3703         // add torch first
3704         InventoryItem *item = new MaterialItem(CONTENT_TORCH, 1);
3705         player->inventory.addItem("main", item);
3706         
3707         // Then others
3708         for(u16 i=0; i<USEFUL_CONTENT_COUNT; i++)
3709         {
3710                 // Skip some materials
3711                 if(i == CONTENT_WATER || i == CONTENT_TORCH
3712                         || i == CONTENT_COALSTONE)
3713                         continue;
3714
3715                 InventoryItem *item = new MaterialItem(i, 1);
3716                 player->inventory.addItem("main", item);
3717         }
3718 #endif
3719
3720         /*// Sign
3721         {
3722                 InventoryItem *item = new MapBlockObjectItem("Sign Example text");
3723                 void* r = player->inventory.addItem("main", item);
3724                 assert(r == NULL);
3725         }*/
3726 }
3727
3728 Player *Server::emergePlayer(const char *name, const char *password,
3729                 u16 peer_id)
3730 {
3731         /*
3732                 Try to get an existing player
3733         */
3734         Player *player = m_env.getPlayer(name);
3735         if(player != NULL)
3736         {
3737                 // If player is already connected, cancel
3738                 if(player->peer_id != 0)
3739                 {
3740                         dstream<<"emergePlayer(): Player already connected"<<std::endl;
3741                         return NULL;
3742                 }
3743
3744                 // Got one.
3745                 player->peer_id = peer_id;
3746                 
3747                 // Reset inventory to creative if in creative mode
3748                 if(g_settings.getBool("creative_mode"))
3749                 {
3750                         setCreativeInventory(player);
3751                 }
3752
3753                 return player;
3754         }
3755
3756         /*
3757                 If player with the wanted peer_id already exists, cancel.
3758         */
3759         if(m_env.getPlayer(peer_id) != NULL)
3760         {
3761                 dstream<<"emergePlayer(): Player with wrong name but same"
3762                                 " peer_id already exists"<<std::endl;
3763                 return NULL;
3764         }
3765         
3766         /*
3767                 Create a new player
3768         */
3769         {
3770                 player = new ServerRemotePlayer();
3771                 //player->peer_id = c.peer_id;
3772                 //player->peer_id = PEER_ID_INEXISTENT;
3773                 player->peer_id = peer_id;
3774                 player->updateName(name);
3775
3776                 /*
3777                         Set player position
3778                 */
3779                 
3780                 dstream<<"Server: Finding spawn place for player \""
3781                                 <<player->getName()<<"\""<<std::endl;
3782
3783                 v2s16 nodepos;
3784 #if 0
3785                 player->setPosition(intToFloat(v3s16(
3786                                 0,
3787                                 45, //64,
3788                                 0
3789                 ), BS));
3790 #endif
3791 #if 1
3792                 s16 groundheight = 0;
3793 #if 1
3794                 // Try to find a good place a few times
3795                 for(s32 i=0; i<1000; i++)
3796                 {
3797                         s32 range = 1 + i;
3798                         // We're going to try to throw the player to this position
3799                         nodepos = v2s16(-range + (myrand()%(range*2)),
3800                                         -range + (myrand()%(range*2)));
3801                         v2s16 sectorpos = getNodeSectorPos(nodepos);
3802                         // Get sector (NOTE: Don't get because it's slow)
3803                         //m_env.getMap().emergeSector(sectorpos);
3804                         // Get ground height at point (fallbacks to heightmap function)
3805                         groundheight = m_env.getServerMap().findGroundLevel(nodepos);
3806                         // Don't go underwater
3807                         if(groundheight < WATER_LEVEL)
3808                         {
3809                                 //dstream<<"-> Underwater"<<std::endl;
3810                                 continue;
3811                         }
3812                         // Don't go to high places
3813                         if(groundheight > WATER_LEVEL + 4)
3814                         {
3815                                 //dstream<<"-> Underwater"<<std::endl;
3816                                 continue;
3817                         }
3818
3819 #if 0
3820 // Doesn't work, generating blocks is a bit too complicated for doing here
3821                         // Get block at point
3822                         v3s16 nodepos3d;
3823                         nodepos3d = v3s16(nodepos.X, groundheight+1, nodepos.Y);
3824                         v3s16 blockpos = getNodeBlockPos(nodepos3d);
3825                         ((ServerMap*)(&m_env.getMap()))->emergeBlock(blockpos);
3826                         // Don't go inside ground
3827                         try{
3828                                 /*v3s16 footpos(nodepos.X, groundheight+1, nodepos.Y);
3829                                 v3s16 headpos(nodepos.X, groundheight+2, nodepos.Y);*/
3830                                 v3s16 footpos = nodepos3d + v3s16(0,0,0);
3831                                 v3s16 headpos = nodepos3d + v3s16(0,1,0);
3832                                 if(m_env.getMap().getNode(footpos).d != CONTENT_AIR
3833                                         || m_env.getMap().getNode(headpos).d != CONTENT_AIR)
3834                                 {
3835                                         dstream<<"-> Inside ground"<<std::endl;
3836                                         // In ground
3837                                         continue;
3838                                 }
3839                         }catch(InvalidPositionException &e)
3840                         {
3841                                 dstream<<"-> Invalid position"<<std::endl;
3842                                 // Ignore invalid position
3843                                 continue;
3844                         }
3845 #endif
3846
3847                         // Found a good place
3848                         dstream<<"Searched through "<<i<<" places."<<std::endl;
3849                         break;
3850                 }
3851 #endif
3852                 
3853                 // If no suitable place was not found, go above water at least.
3854                 if(groundheight < WATER_LEVEL)
3855                         groundheight = WATER_LEVEL;
3856
3857                 player->setPosition(intToFloat(v3s16(
3858                                 nodepos.X,
3859                                 groundheight + 5, // Accomodate mud
3860                                 nodepos.Y
3861                 ), BS));
3862 #endif
3863
3864                 /*
3865                         Add player to environment
3866                 */
3867
3868                 m_env.addPlayer(player);
3869
3870                 /*
3871                         Add stuff to inventory
3872                 */
3873                 
3874                 if(g_settings.getBool("creative_mode"))
3875                 {
3876                         setCreativeInventory(player);
3877                 }
3878                 else
3879                 {
3880                         /*{
3881                                 InventoryItem *item = new ToolItem("WPick", 32000);
3882                                 void* r = player->inventory.addItem("main", item);
3883                                 assert(r == NULL);
3884                         }*/
3885                         /*{
3886                                 InventoryItem *item = new MaterialItem(CONTENT_MESE, 6);
3887                                 void* r = player->inventory.addItem("main", item);
3888                                 assert(r == NULL);
3889                         }
3890                         {
3891                                 InventoryItem *item = new MaterialItem(CONTENT_COALSTONE, 6);
3892                                 void* r = player->inventory.addItem("main", item);
3893                                 assert(r == NULL);
3894                         }
3895                         {
3896                                 InventoryItem *item = new MaterialItem(CONTENT_WOOD, 6);
3897                                 void* r = player->inventory.addItem("main", item);
3898                                 assert(r == NULL);
3899                         }
3900                         {
3901                                 InventoryItem *item = new CraftItem("Stick", 4);
3902                                 void* r = player->inventory.addItem("main", item);
3903                                 assert(r == NULL);
3904                         }
3905                         {
3906                                 InventoryItem *item = new ToolItem("WPick", 32000);
3907                                 void* r = player->inventory.addItem("main", item);
3908                                 assert(r == NULL);
3909                         }
3910                         {
3911                                 InventoryItem *item = new ToolItem("STPick", 32000);
3912                                 void* r = player->inventory.addItem("main", item);
3913                                 assert(r == NULL);
3914                         }*/
3915                         /*// Give some lights
3916                         {
3917                                 InventoryItem *item = new MaterialItem(CONTENT_TORCH, 999);
3918                                 bool r = player->inventory.addItem("main", item);
3919                                 assert(r == true);
3920                         }
3921                         // and some signs
3922                         for(u16 i=0; i<4; i++)
3923                         {
3924                                 InventoryItem *item = new MapBlockObjectItem("Sign Example text");
3925                                 bool r = player->inventory.addItem("main", item);
3926                                 assert(r == true);
3927                         }*/
3928                         /*// Give some other stuff
3929                         {
3930                                 InventoryItem *item = new MaterialItem(CONTENT_TREE, 999);
3931                                 bool r = player->inventory.addItem("main", item);
3932                                 assert(r == true);
3933                         }*/
3934                 }
3935
3936                 return player;
3937                 
3938         } // create new player
3939 }
3940
3941 void Server::handlePeerChange(PeerChange &c)
3942 {
3943         JMutexAutoLock envlock(m_env_mutex);
3944         JMutexAutoLock conlock(m_con_mutex);
3945         
3946         if(c.type == PEER_ADDED)
3947         {
3948                 /*
3949                         Add
3950                 */
3951
3952                 // Error check
3953                 core::map<u16, RemoteClient*>::Node *n;
3954                 n = m_clients.find(c.peer_id);
3955                 // The client shouldn't already exist
3956                 assert(n == NULL);
3957
3958                 // Create client
3959                 RemoteClient *client = new RemoteClient();
3960                 client->peer_id = c.peer_id;
3961                 m_clients.insert(client->peer_id, client);
3962
3963         } // PEER_ADDED
3964         else if(c.type == PEER_REMOVED)
3965         {
3966                 /*
3967                         Delete
3968                 */
3969
3970                 // Error check
3971                 core::map<u16, RemoteClient*>::Node *n;
3972                 n = m_clients.find(c.peer_id);
3973                 // The client should exist
3974                 assert(n != NULL);
3975                 
3976                 // Collect information about leaving in chat
3977                 std::wstring message;
3978                 {
3979                         std::wstring name = L"unknown";
3980                         Player *player = m_env.getPlayer(c.peer_id);
3981                         if(player != NULL)
3982                                 name = narrow_to_wide(player->getName());
3983                         
3984                         message += L"*** ";
3985                         message += name;
3986                         message += L" left game";
3987                         if(c.timeout)
3988                                 message += L" (timed out)";
3989                 }
3990
3991                 /*// Delete player
3992                 {
3993                         m_env.removePlayer(c.peer_id);
3994                 }*/
3995
3996                 // Set player client disconnected
3997                 {
3998                         Player *player = m_env.getPlayer(c.peer_id);
3999                         if(player != NULL)
4000                                 player->peer_id = 0;
4001                 }
4002                 
4003                 // Delete client
4004                 delete m_clients[c.peer_id];
4005                 m_clients.remove(c.peer_id);
4006
4007                 // Send player info to all remaining clients
4008                 SendPlayerInfos();
4009                 
4010                 // Send leave chat message to all remaining clients
4011                 BroadcastChatMessage(message);
4012                 
4013         } // PEER_REMOVED
4014         else
4015         {
4016                 assert(0);
4017         }
4018 }
4019
4020 void Server::handlePeerChanges()
4021 {
4022         while(m_peer_change_queue.size() > 0)
4023         {
4024                 PeerChange c = m_peer_change_queue.pop_front();
4025
4026                 dout_server<<"Server: Handling peer change: "
4027                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4028                                 <<std::endl;
4029
4030                 handlePeerChange(c);
4031         }
4032 }
4033
4034 void dedicated_server_loop(Server &server, bool &kill)
4035 {
4036         DSTACK(__FUNCTION_NAME);
4037         
4038         std::cout<<DTIME<<std::endl;
4039         std::cout<<"========================"<<std::endl;
4040         std::cout<<"Running dedicated server"<<std::endl;
4041         std::cout<<"========================"<<std::endl;
4042         std::cout<<std::endl;
4043
4044         for(;;)
4045         {
4046                 // This is kind of a hack but can be done like this
4047                 // because server.step() is very light
4048                 sleep_ms(30);
4049                 server.step(0.030);
4050
4051                 if(server.getShutdownRequested() || kill)
4052                 {
4053                         std::cout<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4054                         break;
4055                 }
4056
4057                 static int counter = 0;
4058                 counter--;
4059                 if(counter <= 0)
4060                 {
4061                         counter = 10;
4062
4063                         core::list<PlayerInfo> list = server.getPlayerInfo();
4064                         core::list<PlayerInfo>::Iterator i;
4065                         static u32 sum_old = 0;
4066                         u32 sum = PIChecksum(list);
4067                         if(sum != sum_old)
4068                         {
4069                                 std::cout<<DTIME<<"Player info:"<<std::endl;
4070                                 for(i=list.begin(); i!=list.end(); i++)
4071                                 {
4072                                         i->PrintLine(&std::cout);
4073                                 }
4074                         }
4075                         sum_old = sum;
4076                 }
4077         }
4078 }
4079
4080