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