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