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