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