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