]> git.lizzy.rs Git - minetest.git/blob - src/server.cpp
removed furnace menu because it is not needed anymore
[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);
877
878                         blockcount++;
879
880                         /*
881                                 Stop collecting objects if data is already too big
882                         */
883                         // Sum of player and object data sizes
884                         s32 sum = (s32)os.tellp() + 2 + (s32)bos.tellp();
885                         // break out if data too big
886                         if(sum > MAX_OBJECTDATA_SIZE)
887                         {
888                                 goto skip_subsequent;
889                         }
890                         
891                         } //try
892                         catch(InvalidPositionException &e)
893                         {
894                                 // Not in memory
895                                 // Add it to the emerge queue and trigger the thread.
896                                 // Fetch the block only if it is on disk.
897                                 
898                                 // Grab and increment counter
899                                 /*SharedPtr<JMutexAutoLock> lock
900                                                 (m_num_blocks_in_emerge_queue.getLock());
901                                 m_num_blocks_in_emerge_queue.m_value++;*/
902                                 
903                                 // Add to queue as an anonymous fetch from disk
904                                 u8 flags = BLOCK_EMERGE_FLAG_FROMDISK;
905                                 server->m_emerge_queue.addBlock(0, p, flags);
906                                 server->m_emergethread.trigger();
907                         }
908                 }
909         }
910
911 skip_subsequent:
912
913         // Write block count
914         writeU16(buf, blockcount);
915         os.write((char*)buf, 2);
916
917         // Write block objects
918         os<<bos.str();
919
920         /*
921                 Send data
922         */
923         
924         //dstream<<"Server: Sending object data to "<<peer_id<<std::endl;
925
926         // Make data buffer
927         std::string s = os.str();
928         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
929         // Send as unreliable
930         server->m_con.Send(peer_id, 0, data, false);
931 }
932
933 void RemoteClient::GotBlock(v3s16 p)
934 {
935         if(m_blocks_sending.find(p) != NULL)
936                 m_blocks_sending.remove(p);
937         else
938         {
939                 /*dstream<<"RemoteClient::GotBlock(): Didn't find in"
940                                 " m_blocks_sending"<<std::endl;*/
941                 m_excess_gotblocks++;
942         }
943         m_blocks_sent.insert(p, true);
944 }
945
946 void RemoteClient::SentBlock(v3s16 p)
947 {
948         if(m_blocks_sending.find(p) == NULL)
949                 m_blocks_sending.insert(p, 0.0);
950         else
951                 dstream<<"RemoteClient::SentBlock(): Sent block"
952                                 " already in m_blocks_sending"<<std::endl;
953 }
954
955 void RemoteClient::SetBlockNotSent(v3s16 p)
956 {
957         m_nearest_unsent_d = 0;
958         
959         if(m_blocks_sending.find(p) != NULL)
960                 m_blocks_sending.remove(p);
961         if(m_blocks_sent.find(p) != NULL)
962                 m_blocks_sent.remove(p);
963 }
964
965 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
966 {
967         m_nearest_unsent_d = 0;
968         
969         for(core::map<v3s16, MapBlock*>::Iterator
970                         i = blocks.getIterator();
971                         i.atEnd()==false; i++)
972         {
973                 v3s16 p = i.getNode()->getKey();
974
975                 if(m_blocks_sending.find(p) != NULL)
976                         m_blocks_sending.remove(p);
977                 if(m_blocks_sent.find(p) != NULL)
978                         m_blocks_sent.remove(p);
979         }
980 }
981
982 /*
983         PlayerInfo
984 */
985
986 PlayerInfo::PlayerInfo()
987 {
988         name[0] = 0;
989         avg_rtt = 0;
990 }
991
992 void PlayerInfo::PrintLine(std::ostream *s)
993 {
994         (*s)<<id<<": ";
995         (*s)<<"\""<<name<<"\" ("
996                         <<(position.X/10)<<","<<(position.Y/10)
997                         <<","<<(position.Z/10)<<") ";
998         address.print(s);
999         (*s)<<" avg_rtt="<<avg_rtt;
1000         (*s)<<std::endl;
1001 }
1002
1003 u32 PIChecksum(core::list<PlayerInfo> &l)
1004 {
1005         core::list<PlayerInfo>::Iterator i;
1006         u32 checksum = 1;
1007         u32 a = 10;
1008         for(i=l.begin(); i!=l.end(); i++)
1009         {
1010                 checksum += a * (i->id+1);
1011                 checksum ^= 0x435aafcd;
1012                 a *= 10;
1013         }
1014         return checksum;
1015 }
1016
1017 /*
1018         Server
1019 */
1020
1021 Server::Server(
1022                 std::string mapsavedir
1023         ):
1024         m_env(new ServerMap(mapsavedir), this),
1025         m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
1026         m_authmanager(mapsavedir+"/auth.txt"),
1027         m_thread(this),
1028         m_emergethread(this),
1029         m_time_counter(0),
1030         m_time_of_day_send_timer(0),
1031         m_uptime(0),
1032         m_mapsavedir(mapsavedir),
1033         m_shutdown_requested(false),
1034         m_ignore_map_edit_events(false),
1035         m_ignore_map_edit_events_peer_id(0)
1036 {
1037         m_liquid_transform_timer = 0.0;
1038         m_print_info_timer = 0.0;
1039         m_objectdata_timer = 0.0;
1040         m_emergethread_trigger_timer = 0.0;
1041         m_savemap_timer = 0.0;
1042         
1043         m_env_mutex.Init();
1044         m_con_mutex.Init();
1045         m_step_dtime_mutex.Init();
1046         m_step_dtime = 0.0;
1047         
1048         // Register us to receive map edit events
1049         m_env.getMap().addEventReceiver(this);
1050
1051         // If file exists, load environment metadata
1052         if(fs::PathExists(m_mapsavedir+"/env_meta.txt"))
1053         {
1054                 dstream<<"Server: Loading environment metadata"<<std::endl;
1055                 m_env.loadMeta(m_mapsavedir);
1056         }
1057
1058         // Load players
1059         dstream<<"Server: Loading players"<<std::endl;
1060         m_env.deSerializePlayers(m_mapsavedir);
1061 }
1062
1063 Server::~Server()
1064 {
1065         dstream<<"Server::~Server()"<<std::endl;
1066
1067         /*
1068                 Send shutdown message
1069         */
1070         {
1071                 JMutexAutoLock conlock(m_con_mutex);
1072                 
1073                 std::wstring line = L"*** Server shutting down";
1074
1075                 /*
1076                         Send the message to clients
1077                 */
1078                 for(core::map<u16, RemoteClient*>::Iterator
1079                         i = m_clients.getIterator();
1080                         i.atEnd() == false; i++)
1081                 {
1082                         // Get client and check that it is valid
1083                         RemoteClient *client = i.getNode()->getValue();
1084                         assert(client->peer_id == i.getNode()->getKey());
1085                         if(client->serialization_version == SER_FMT_VER_INVALID)
1086                                 continue;
1087
1088                         try{
1089                                 SendChatMessage(client->peer_id, line);
1090                         }
1091                         catch(con::PeerNotFoundException &e)
1092                         {}
1093                 }
1094         }
1095
1096         /*
1097                 Save players
1098         */
1099         dstream<<"Server: Saving players"<<std::endl;
1100         m_env.serializePlayers(m_mapsavedir);
1101
1102         /*
1103                 Save environment metadata
1104         */
1105         dstream<<"Server: Saving environment metadata"<<std::endl;
1106         m_env.saveMeta(m_mapsavedir);
1107         
1108         /*
1109                 Stop threads
1110         */
1111         stop();
1112         
1113         /*
1114                 Delete clients
1115         */
1116         {
1117                 JMutexAutoLock clientslock(m_con_mutex);
1118
1119                 for(core::map<u16, RemoteClient*>::Iterator
1120                         i = m_clients.getIterator();
1121                         i.atEnd() == false; i++)
1122                 {
1123                         /*// Delete player
1124                         // NOTE: These are removed by env destructor
1125                         {
1126                                 u16 peer_id = i.getNode()->getKey();
1127                                 JMutexAutoLock envlock(m_env_mutex);
1128                                 m_env.removePlayer(peer_id);
1129                         }*/
1130                         
1131                         // Delete client
1132                         delete i.getNode()->getValue();
1133                 }
1134         }
1135 }
1136
1137 void Server::start(unsigned short port)
1138 {
1139         DSTACK(__FUNCTION_NAME);
1140         // Stop thread if already running
1141         m_thread.stop();
1142         
1143         // Initialize connection
1144         m_con.setTimeoutMs(30);
1145         m_con.Serve(port);
1146
1147         // Start thread
1148         m_thread.setRun(true);
1149         m_thread.Start();
1150         
1151         dout_server<<"Server: Started on port "<<port<<std::endl;
1152 }
1153
1154 void Server::stop()
1155 {
1156         DSTACK(__FUNCTION_NAME);
1157
1158         // Stop threads (set run=false first so both start stopping)
1159         m_thread.setRun(false);
1160         m_emergethread.setRun(false);
1161         m_thread.stop();
1162         m_emergethread.stop();
1163         
1164         dout_server<<"Server: Threads stopped"<<std::endl;
1165 }
1166
1167 void Server::step(float dtime)
1168 {
1169         DSTACK(__FUNCTION_NAME);
1170         // Limit a bit
1171         if(dtime > 2.0)
1172                 dtime = 2.0;
1173         {
1174                 JMutexAutoLock lock(m_step_dtime_mutex);
1175                 m_step_dtime += dtime;
1176         }
1177 }
1178
1179 void Server::AsyncRunStep()
1180 {
1181         DSTACK(__FUNCTION_NAME);
1182         
1183         float dtime;
1184         {
1185                 JMutexAutoLock lock1(m_step_dtime_mutex);
1186                 dtime = m_step_dtime;
1187         }
1188         
1189         {
1190                 ScopeProfiler sp(&g_profiler, "Server: selecting and sending "
1191                                 "blocks to clients");
1192                 // Send blocks to clients
1193                 SendBlocks(dtime);
1194         }
1195         
1196         if(dtime < 0.001)
1197                 return;
1198
1199         //dstream<<"Server steps "<<dtime<<std::endl;
1200         //dstream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1201         
1202         {
1203                 JMutexAutoLock lock1(m_step_dtime_mutex);
1204                 m_step_dtime -= dtime;
1205         }
1206
1207         /*
1208                 Update uptime
1209         */
1210         {
1211                 m_uptime.set(m_uptime.get() + dtime);
1212         }
1213         
1214         /*
1215                 Update m_time_of_day and overall game time
1216         */
1217         {
1218                 JMutexAutoLock envlock(m_env_mutex);
1219
1220                 m_time_counter += dtime;
1221                 f32 speed = g_settings.getFloat("time_speed") * 24000./(24.*3600);
1222                 u32 units = (u32)(m_time_counter*speed);
1223                 m_time_counter -= (f32)units / speed;
1224                 
1225                 m_env.setTimeOfDay((m_env.getTimeOfDay() + units) % 24000);
1226                 
1227                 //dstream<<"Server: m_time_of_day = "<<m_time_of_day.get()<<std::endl;
1228
1229                 /*
1230                         Send to clients at constant intervals
1231                 */
1232
1233                 m_time_of_day_send_timer -= dtime;
1234                 if(m_time_of_day_send_timer < 0.0)
1235                 {
1236                         m_time_of_day_send_timer = g_settings.getFloat("time_send_interval");
1237
1238                         //JMutexAutoLock envlock(m_env_mutex);
1239                         JMutexAutoLock conlock(m_con_mutex);
1240
1241                         for(core::map<u16, RemoteClient*>::Iterator
1242                                 i = m_clients.getIterator();
1243                                 i.atEnd() == false; i++)
1244                         {
1245                                 RemoteClient *client = i.getNode()->getValue();
1246                                 //Player *player = m_env.getPlayer(client->peer_id);
1247                                 
1248                                 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1249                                                 m_env.getTimeOfDay());
1250                                 // Send as reliable
1251                                 m_con.Send(client->peer_id, 0, data, true);
1252                         }
1253                 }
1254         }
1255
1256         {
1257                 // Process connection's timeouts
1258                 JMutexAutoLock lock2(m_con_mutex);
1259                 ScopeProfiler sp(&g_profiler, "Server: connection timeout processing");
1260                 m_con.RunTimeouts(dtime);
1261         }
1262         
1263         {
1264                 // This has to be called so that the client list gets synced
1265                 // with the peer list of the connection
1266                 ScopeProfiler sp(&g_profiler, "Server: peer change handling");
1267                 handlePeerChanges();
1268         }
1269
1270         {
1271                 // Step environment
1272                 // This also runs Map's timers
1273                 JMutexAutoLock lock(m_env_mutex);
1274                 ScopeProfiler sp(&g_profiler, "Server: environment step");
1275                 m_env.step(dtime);
1276         }
1277         
1278         /*
1279                 Do background stuff
1280         */
1281         
1282         /*
1283                 Transform liquids
1284         */
1285         m_liquid_transform_timer += dtime;
1286         if(m_liquid_transform_timer >= 1.00)
1287         {
1288                 m_liquid_transform_timer -= 1.00;
1289                 
1290                 JMutexAutoLock lock(m_env_mutex);
1291
1292                 ScopeProfiler sp(&g_profiler, "Server: liquid transform");
1293
1294                 core::map<v3s16, MapBlock*> modified_blocks;
1295                 m_env.getMap().transformLiquids(modified_blocks);
1296 #if 0           
1297                 /*
1298                         Update lighting
1299                 */
1300                 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1301                 ServerMap &map = ((ServerMap&)m_env.getMap());
1302                 map.updateLighting(modified_blocks, lighting_modified_blocks);
1303                 
1304                 // Add blocks modified by lighting to modified_blocks
1305                 for(core::map<v3s16, MapBlock*>::Iterator
1306                                 i = lighting_modified_blocks.getIterator();
1307                                 i.atEnd() == false; i++)
1308                 {
1309                         MapBlock *block = i.getNode()->getValue();
1310                         modified_blocks.insert(block->getPos(), block);
1311                 }
1312 #endif
1313                 /*
1314                         Set the modified blocks unsent for all the clients
1315                 */
1316                 
1317                 JMutexAutoLock lock2(m_con_mutex);
1318
1319                 for(core::map<u16, RemoteClient*>::Iterator
1320                                 i = m_clients.getIterator();
1321                                 i.atEnd() == false; i++)
1322                 {
1323                         RemoteClient *client = i.getNode()->getValue();
1324                         
1325                         if(modified_blocks.size() > 0)
1326                         {
1327                                 // Remove block from sent history
1328                                 client->SetBlocksNotSent(modified_blocks);
1329                         }
1330                 }
1331         }
1332
1333         // Periodically print some info
1334         {
1335                 float &counter = m_print_info_timer;
1336                 counter += dtime;
1337                 if(counter >= 30.0)
1338                 {
1339                         counter = 0.0;
1340
1341                         JMutexAutoLock lock2(m_con_mutex);
1342
1343                         for(core::map<u16, RemoteClient*>::Iterator
1344                                 i = m_clients.getIterator();
1345                                 i.atEnd() == false; i++)
1346                         {
1347                                 //u16 peer_id = i.getNode()->getKey();
1348                                 RemoteClient *client = i.getNode()->getValue();
1349                                 Player *player = m_env.getPlayer(client->peer_id);
1350                                 if(player==NULL)
1351                                         continue;
1352                                 std::cout<<player->getName()<<"\t";
1353                                 client->PrintInfo(std::cout);
1354                         }
1355                 }
1356         }
1357
1358         //if(g_settings.getBool("enable_experimental"))
1359         {
1360
1361         /*
1362                 Check added and deleted active objects
1363         */
1364         {
1365                 //dstream<<"Server: Checking added and deleted active objects"<<std::endl;
1366                 JMutexAutoLock envlock(m_env_mutex);
1367                 JMutexAutoLock conlock(m_con_mutex);
1368
1369                 ScopeProfiler sp(&g_profiler, "Server: checking added and deleted objects");
1370
1371                 // Radius inside which objects are active
1372                 s16 radius = 32;
1373
1374                 for(core::map<u16, RemoteClient*>::Iterator
1375                         i = m_clients.getIterator();
1376                         i.atEnd() == false; i++)
1377                 {
1378                         RemoteClient *client = i.getNode()->getValue();
1379                         Player *player = m_env.getPlayer(client->peer_id);
1380                         if(player==NULL)
1381                         {
1382                                 // This can happen if the client timeouts somehow
1383                                 /*dstream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1384                                                 <<client->peer_id
1385                                                 <<" has no associated player"<<std::endl;*/
1386                                 continue;
1387                         }
1388                         v3s16 pos = floatToInt(player->getPosition(), BS);
1389
1390                         core::map<u16, bool> removed_objects;
1391                         core::map<u16, bool> added_objects;
1392                         m_env.getRemovedActiveObjects(pos, radius,
1393                                         client->m_known_objects, removed_objects);
1394                         m_env.getAddedActiveObjects(pos, radius,
1395                                         client->m_known_objects, added_objects);
1396                         
1397                         // Ignore if nothing happened
1398                         if(removed_objects.size() == 0 && added_objects.size() == 0)
1399                         {
1400                                 //dstream<<"INFO: active objects: none changed"<<std::endl;
1401                                 continue;
1402                         }
1403                         
1404                         std::string data_buffer;
1405
1406                         char buf[4];
1407                         
1408                         // Handle removed objects
1409                         writeU16((u8*)buf, removed_objects.size());
1410                         data_buffer.append(buf, 2);
1411                         for(core::map<u16, bool>::Iterator
1412                                         i = removed_objects.getIterator();
1413                                         i.atEnd()==false; i++)
1414                         {
1415                                 // Get object
1416                                 u16 id = i.getNode()->getKey();
1417                                 ServerActiveObject* obj = m_env.getActiveObject(id);
1418
1419                                 // Add to data buffer for sending
1420                                 writeU16((u8*)buf, i.getNode()->getKey());
1421                                 data_buffer.append(buf, 2);
1422                                 
1423                                 // Remove from known objects
1424                                 client->m_known_objects.remove(i.getNode()->getKey());
1425
1426                                 if(obj && obj->m_known_by_count > 0)
1427                                         obj->m_known_by_count--;
1428                         }
1429
1430                         // Handle added objects
1431                         writeU16((u8*)buf, added_objects.size());
1432                         data_buffer.append(buf, 2);
1433                         for(core::map<u16, bool>::Iterator
1434                                         i = added_objects.getIterator();
1435                                         i.atEnd()==false; i++)
1436                         {
1437                                 // Get object
1438                                 u16 id = i.getNode()->getKey();
1439                                 ServerActiveObject* obj = m_env.getActiveObject(id);
1440                                 
1441                                 // Get object type
1442                                 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1443                                 if(obj == NULL)
1444                                         dstream<<"WARNING: "<<__FUNCTION_NAME
1445                                                         <<": NULL object"<<std::endl;
1446                                 else
1447                                         type = obj->getType();
1448
1449                                 // Add to data buffer for sending
1450                                 writeU16((u8*)buf, id);
1451                                 data_buffer.append(buf, 2);
1452                                 writeU8((u8*)buf, type);
1453                                 data_buffer.append(buf, 1);
1454                                 
1455                                 if(obj)
1456                                         data_buffer.append(serializeLongString(
1457                                                         obj->getClientInitializationData()));
1458                                 else
1459                                         data_buffer.append(serializeLongString(""));
1460
1461                                 // Add to known objects
1462                                 client->m_known_objects.insert(i.getNode()->getKey(), false);
1463
1464                                 if(obj)
1465                                         obj->m_known_by_count++;
1466                         }
1467
1468                         // Send packet
1469                         SharedBuffer<u8> reply(2 + data_buffer.size());
1470                         writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1471                         memcpy((char*)&reply[2], data_buffer.c_str(),
1472                                         data_buffer.size());
1473                         // Send as reliable
1474                         m_con.Send(client->peer_id, 0, reply, true);
1475
1476                         dstream<<"INFO: Server: Sent object remove/add: "
1477                                         <<removed_objects.size()<<" removed, "
1478                                         <<added_objects.size()<<" added, "
1479                                         <<"packet size is "<<reply.getSize()<<std::endl;
1480                 }
1481
1482 #if 0
1483                 /*
1484                         Collect a list of all the objects known by the clients
1485                         and report it back to the environment.
1486                 */
1487
1488                 core::map<u16, bool> all_known_objects;
1489
1490                 for(core::map<u16, RemoteClient*>::Iterator
1491                         i = m_clients.getIterator();
1492                         i.atEnd() == false; i++)
1493                 {
1494                         RemoteClient *client = i.getNode()->getValue();
1495                         // Go through all known objects of client
1496                         for(core::map<u16, bool>::Iterator
1497                                         i = client->m_known_objects.getIterator();
1498                                         i.atEnd()==false; i++)
1499                         {
1500                                 u16 id = i.getNode()->getKey();
1501                                 all_known_objects[id] = true;
1502                         }
1503                 }
1504                 
1505                 m_env.setKnownActiveObjects(whatever);
1506 #endif
1507
1508         }
1509
1510         /*
1511                 Send object messages
1512         */
1513         {
1514                 JMutexAutoLock envlock(m_env_mutex);
1515                 JMutexAutoLock conlock(m_con_mutex);
1516
1517                 ScopeProfiler sp(&g_profiler, "Server: sending object messages");
1518
1519                 // Key = object id
1520                 // Value = data sent by object
1521                 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1522
1523                 // Get active object messages from environment
1524                 for(;;)
1525                 {
1526                         ActiveObjectMessage aom = m_env.getActiveObjectMessage();
1527                         if(aom.id == 0)
1528                                 break;
1529                         
1530                         core::list<ActiveObjectMessage>* message_list = NULL;
1531                         core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1532                         n = buffered_messages.find(aom.id);
1533                         if(n == NULL)
1534                         {
1535                                 message_list = new core::list<ActiveObjectMessage>;
1536                                 buffered_messages.insert(aom.id, message_list);
1537                         }
1538                         else
1539                         {
1540                                 message_list = n->getValue();
1541                         }
1542                         message_list->push_back(aom);
1543                 }
1544                 
1545                 // Route data to every client
1546                 for(core::map<u16, RemoteClient*>::Iterator
1547                         i = m_clients.getIterator();
1548                         i.atEnd()==false; i++)
1549                 {
1550                         RemoteClient *client = i.getNode()->getValue();
1551                         std::string reliable_data;
1552                         std::string unreliable_data;
1553                         // Go through all objects in message buffer
1554                         for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1555                                         j = buffered_messages.getIterator();
1556                                         j.atEnd()==false; j++)
1557                         {
1558                                 // If object is not known by client, skip it
1559                                 u16 id = j.getNode()->getKey();
1560                                 if(client->m_known_objects.find(id) == NULL)
1561                                         continue;
1562                                 // Get message list of object
1563                                 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1564                                 // Go through every message
1565                                 for(core::list<ActiveObjectMessage>::Iterator
1566                                                 k = list->begin(); k != list->end(); k++)
1567                                 {
1568                                         // Compose the full new data with header
1569                                         ActiveObjectMessage aom = *k;
1570                                         std::string new_data;
1571                                         // Add object id
1572                                         char buf[2];
1573                                         writeU16((u8*)&buf[0], aom.id);
1574                                         new_data.append(buf, 2);
1575                                         // Add data
1576                                         new_data += serializeString(aom.datastring);
1577                                         // Add data to buffer
1578                                         if(aom.reliable)
1579                                                 reliable_data += new_data;
1580                                         else
1581                                                 unreliable_data += new_data;
1582                                 }
1583                         }
1584                         /*
1585                                 reliable_data and unreliable_data are now ready.
1586                                 Send them.
1587                         */
1588                         if(reliable_data.size() > 0)
1589                         {
1590                                 SharedBuffer<u8> reply(2 + reliable_data.size());
1591                                 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1592                                 memcpy((char*)&reply[2], reliable_data.c_str(),
1593                                                 reliable_data.size());
1594                                 // Send as reliable
1595                                 m_con.Send(client->peer_id, 0, reply, true);
1596                         }
1597                         if(unreliable_data.size() > 0)
1598                         {
1599                                 SharedBuffer<u8> reply(2 + unreliable_data.size());
1600                                 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1601                                 memcpy((char*)&reply[2], unreliable_data.c_str(),
1602                                                 unreliable_data.size());
1603                                 // Send as unreliable
1604                                 m_con.Send(client->peer_id, 0, reply, false);
1605                         }
1606
1607                         /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1608                         {
1609                                 dstream<<"INFO: Server: Size of object message data: "
1610                                                 <<"reliable: "<<reliable_data.size()
1611                                                 <<", unreliable: "<<unreliable_data.size()
1612                                                 <<std::endl;
1613                         }*/
1614                 }
1615
1616                 // Clear buffered_messages
1617                 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1618                                 i = buffered_messages.getIterator();
1619                                 i.atEnd()==false; i++)
1620                 {
1621                         delete i.getNode()->getValue();
1622                 }
1623         }
1624
1625         } // enable_experimental
1626
1627         /*
1628                 Send queued-for-sending map edit events.
1629         */
1630         {
1631                 while(m_unsent_map_edit_queue.size() != 0)
1632                 {
1633                         MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1634
1635                         if(event->type == MEET_ADDNODE)
1636                         {
1637                                 dstream<<"Server: MEET_ADDNODE"<<std::endl;
1638                                 sendAddNode(event->p, event->n, event->already_known_by_peer);
1639                         }
1640                         else if(event->type == MEET_REMOVENODE)
1641                         {
1642                                 dstream<<"Server: MEET_REMOVENODE"<<std::endl;
1643                                 sendRemoveNode(event->p, event->already_known_by_peer);
1644                         }
1645                         else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1646                         {
1647                                 dstream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1648                                 setBlockNotSent(event->p);
1649                         }
1650                         else if(event->type == MEET_OTHER)
1651                         {
1652                                 dstream<<"WARNING: Server: MEET_OTHER not implemented"
1653                                                 <<std::endl;
1654                         }
1655                         else
1656                         {
1657                                 dstream<<"WARNING: Server: Unknown MapEditEvent "
1658                                                 <<((u32)event->type)<<std::endl;
1659                         }
1660
1661                         delete event;
1662                 }
1663         }
1664
1665         /*
1666                 Send object positions
1667                 TODO: Get rid of MapBlockObjects
1668         */
1669         {
1670                 float &counter = m_objectdata_timer;
1671                 counter += dtime;
1672                 if(counter >= g_settings.getFloat("objectdata_interval"))
1673                 {
1674                         JMutexAutoLock lock1(m_env_mutex);
1675                         JMutexAutoLock lock2(m_con_mutex);
1676
1677                         ScopeProfiler sp(&g_profiler, "Server: sending mbo positions");
1678
1679                         SendObjectData(counter);
1680
1681                         counter = 0.0;
1682                 }
1683         }
1684         
1685         /*
1686                 Step node metadata
1687                 TODO: Move to ServerEnvironment and utilize active block stuff
1688         */
1689         /*{
1690                 //TimeTaker timer("Step node metadata");
1691
1692                 JMutexAutoLock envlock(m_env_mutex);
1693                 JMutexAutoLock conlock(m_con_mutex);
1694
1695                 ScopeProfiler sp(&g_profiler, "Server: stepping node metadata");
1696
1697                 core::map<v3s16, MapBlock*> changed_blocks;
1698                 m_env.getMap().nodeMetadataStep(dtime, changed_blocks);
1699                 
1700                 // Use setBlockNotSent
1701
1702                 for(core::map<v3s16, MapBlock*>::Iterator
1703                                 i = changed_blocks.getIterator();
1704                                 i.atEnd() == false; i++)
1705                 {
1706                         MapBlock *block = i.getNode()->getValue();
1707
1708                         for(core::map<u16, RemoteClient*>::Iterator
1709                                 i = m_clients.getIterator();
1710                                 i.atEnd()==false; i++)
1711                         {
1712                                 RemoteClient *client = i.getNode()->getValue();
1713                                 client->SetBlockNotSent(block->getPos());
1714                         }
1715                 }
1716         }*/
1717                 
1718         /*
1719                 Trigger emergethread (it somehow gets to a non-triggered but
1720                 bysy state sometimes)
1721         */
1722         {
1723                 float &counter = m_emergethread_trigger_timer;
1724                 counter += dtime;
1725                 if(counter >= 2.0)
1726                 {
1727                         counter = 0.0;
1728                         
1729                         m_emergethread.trigger();
1730                 }
1731         }
1732
1733         // Save map, players and auth stuff
1734         {
1735                 float &counter = m_savemap_timer;
1736                 counter += dtime;
1737                 if(counter >= g_settings.getFloat("server_map_save_interval"))
1738                 {
1739                         counter = 0.0;
1740
1741                         ScopeProfiler sp(&g_profiler, "Server: saving stuff");
1742
1743                         // Auth stuff
1744                         if(m_authmanager.isModified())
1745                                 m_authmanager.save();
1746                         
1747                         // Map
1748                         JMutexAutoLock lock(m_env_mutex);
1749                         if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == true)
1750                         {
1751                                 // Save only changed parts
1752                                 m_env.getMap().save(true);
1753
1754                                 // Delete unused sectors
1755                                 u32 deleted_count = m_env.getMap().deleteUnusedSectors(
1756                                                 g_settings.getFloat("server_unload_unused_sectors_timeout"));
1757                                 if(deleted_count > 0)
1758                                 {
1759                                         dout_server<<"Server: Unloaded "<<deleted_count
1760                                                         <<" sectors from memory"<<std::endl;
1761                                 }
1762
1763                                 // Save players
1764                                 m_env.serializePlayers(m_mapsavedir);
1765                                 
1766                                 // Save environment metadata
1767                                 m_env.saveMeta(m_mapsavedir);
1768                         }
1769                 }
1770         }
1771 }
1772
1773 void Server::Receive()
1774 {
1775         DSTACK(__FUNCTION_NAME);
1776         u32 data_maxsize = 10000;
1777         Buffer<u8> data(data_maxsize);
1778         u16 peer_id;
1779         u32 datasize;
1780         try{
1781                 {
1782                         JMutexAutoLock conlock(m_con_mutex);
1783                         datasize = m_con.Receive(peer_id, *data, data_maxsize);
1784                 }
1785
1786                 // This has to be called so that the client list gets synced
1787                 // with the peer list of the connection
1788                 handlePeerChanges();
1789
1790                 ProcessData(*data, datasize, peer_id);
1791         }
1792         catch(con::InvalidIncomingDataException &e)
1793         {
1794                 derr_server<<"Server::Receive(): "
1795                                 "InvalidIncomingDataException: what()="
1796                                 <<e.what()<<std::endl;
1797         }
1798         catch(con::PeerNotFoundException &e)
1799         {
1800                 //NOTE: This is not needed anymore
1801                 
1802                 // The peer has been disconnected.
1803                 // Find the associated player and remove it.
1804
1805                 /*JMutexAutoLock envlock(m_env_mutex);
1806
1807                 dout_server<<"ServerThread: peer_id="<<peer_id
1808                                 <<" has apparently closed connection. "
1809                                 <<"Removing player."<<std::endl;
1810
1811                 m_env.removePlayer(peer_id);*/
1812         }
1813 }
1814
1815 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1816 {
1817         DSTACK(__FUNCTION_NAME);
1818         // Environment is locked first.
1819         JMutexAutoLock envlock(m_env_mutex);
1820         JMutexAutoLock conlock(m_con_mutex);
1821         
1822         con::Peer *peer;
1823         try{
1824                 peer = m_con.GetPeer(peer_id);
1825         }
1826         catch(con::PeerNotFoundException &e)
1827         {
1828                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1829                                 <<peer_id<<" not found"<<std::endl;
1830                 return;
1831         }
1832         
1833         u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1834
1835         try
1836         {
1837
1838         if(datasize < 2)
1839                 return;
1840
1841         ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1842         
1843         if(command == TOSERVER_INIT)
1844         {
1845                 // [0] u16 TOSERVER_INIT
1846                 // [2] u8 SER_FMT_VER_HIGHEST
1847                 // [3] u8[20] player_name
1848                 // [23] u8[28] password <--- can be sent without this, from old versions
1849
1850                 if(datasize < 2+1+PLAYERNAME_SIZE)
1851                         return;
1852
1853                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1854                                 <<peer->id<<std::endl;
1855
1856                 // First byte after command is maximum supported
1857                 // serialization version
1858                 u8 client_max = data[2];
1859                 u8 our_max = SER_FMT_VER_HIGHEST;
1860                 // Use the highest version supported by both
1861                 u8 deployed = core::min_(client_max, our_max);
1862                 // If it's lower than the lowest supported, give up.
1863                 if(deployed < SER_FMT_VER_LOWEST)
1864                         deployed = SER_FMT_VER_INVALID;
1865
1866                 //peer->serialization_version = deployed;
1867                 getClient(peer->id)->pending_serialization_version = deployed;
1868
1869                 if(deployed == SER_FMT_VER_INVALID)
1870                 {
1871                         derr_server<<DTIME<<"Server: Cannot negotiate "
1872                                         "serialization version with peer "
1873                                         <<peer_id<<std::endl;
1874                         return;
1875                 }
1876
1877                 /*
1878                         Set up player
1879                 */
1880                 
1881                 // Get player name
1882                 char playername[PLAYERNAME_SIZE];
1883                 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1884                 {
1885                         playername[i] = data[3+i];
1886                 }
1887                 playername[PLAYERNAME_SIZE-1] = 0;
1888                 
1889                 if(playername[0]=='\0')
1890                 {
1891                         derr_server<<DTIME<<"Server: Player has empty name"<<std::endl;
1892                         SendAccessDenied(m_con, peer_id,
1893                                         L"Empty name");
1894                         return;
1895                 }
1896
1897                 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1898                 {
1899                         derr_server<<DTIME<<"Server: Player has invalid name"<<std::endl;
1900                         SendAccessDenied(m_con, peer_id,
1901                                         L"Name contains unallowed characters");
1902                         return;
1903                 }
1904
1905                 // Get password
1906                 char password[PASSWORD_SIZE];
1907                 if(datasize == 2+1+PLAYERNAME_SIZE)
1908                 {
1909                         // old version - assume blank password
1910                         password[0] = 0;
1911                 }
1912                 else
1913                 {
1914                                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1915                                 {
1916                                         password[i] = data[23+i];
1917                                 }
1918                                 password[PASSWORD_SIZE-1] = 0;
1919                 }
1920                 
1921                 std::string checkpwd;
1922                 if(m_authmanager.exists(playername))
1923                 {
1924                         checkpwd = m_authmanager.getPassword(playername);
1925                 }
1926                 else
1927                 {
1928                         checkpwd = g_settings.get("default_password");
1929                 }
1930                 
1931                 if(password != checkpwd && checkpwd != "")
1932                 {
1933                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
1934                                         <<": supplied invalid password for "
1935                                         <<playername<<std::endl;
1936                         SendAccessDenied(m_con, peer_id, L"Invalid password");
1937                         return;
1938                 }
1939                 
1940                 // Add player to auth manager
1941                 if(m_authmanager.exists(playername) == false)
1942                 {
1943                         derr_server<<DTIME<<"Server: adding player "<<playername
1944                                         <<" to auth manager"<<std::endl;
1945                         m_authmanager.add(playername);
1946                         m_authmanager.setPassword(playername, checkpwd);
1947                         m_authmanager.setPrivs(playername,
1948                                         stringToPrivs(g_settings.get("default_privs")));
1949                         m_authmanager.save();
1950                 }
1951
1952                 // Get player
1953                 Player *player = emergePlayer(playername, password, peer_id);
1954
1955
1956                 /*{
1957                         // DEBUG: Test serialization
1958                         std::ostringstream test_os;
1959                         player->serialize(test_os);
1960                         dstream<<"Player serialization test: \""<<test_os.str()
1961                                         <<"\""<<std::endl;
1962                         std::istringstream test_is(test_os.str());
1963                         player->deSerialize(test_is);
1964                 }*/
1965
1966                 // If failed, cancel
1967                 if(player == NULL)
1968                 {
1969                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
1970                                         <<": failed to emerge player"<<std::endl;
1971                         return;
1972                 }
1973
1974                 /*
1975                 // If a client is already connected to the player, cancel
1976                 if(player->peer_id != 0)
1977                 {
1978                         derr_server<<DTIME<<"Server: peer_id="<<peer_id
1979                                         <<" tried to connect to "
1980                                         "an already connected player (peer_id="
1981                                         <<player->peer_id<<")"<<std::endl;
1982                         return;
1983                 }
1984                 // Set client of player
1985                 player->peer_id = peer_id;
1986                 */
1987
1988                 // Check if player doesn't exist
1989                 if(player == NULL)
1990                         throw con::InvalidIncomingDataException
1991                                 ("Server::ProcessData(): INIT: Player doesn't exist");
1992
1993                 /*// update name if it was supplied
1994                 if(datasize >= 20+3)
1995                 {
1996                         data[20+3-1] = 0;
1997                         player->updateName((const char*)&data[3]);
1998                 }*/
1999                 
2000                 /*
2001                         Answer with a TOCLIENT_INIT
2002                 */
2003                 {
2004                         SharedBuffer<u8> reply(2+1+6+8);
2005                         writeU16(&reply[0], TOCLIENT_INIT);
2006                         writeU8(&reply[2], deployed);
2007                         writeV3S16(&reply[2+1], floatToInt(player->getPosition()+v3f(0,BS/2,0), BS));
2008                         writeU64(&reply[2+1+6], m_env.getServerMap().getSeed());
2009                         
2010                         // Send as reliable
2011                         m_con.Send(peer_id, 0, reply, true);
2012                 }
2013
2014                 /*
2015                         Send complete position information
2016                 */
2017                 SendMovePlayer(player);
2018
2019                 return;
2020         }
2021
2022         if(command == TOSERVER_INIT2)
2023         {
2024                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
2025                                 <<peer->id<<std::endl;
2026
2027
2028                 getClient(peer->id)->serialization_version
2029                                 = getClient(peer->id)->pending_serialization_version;
2030
2031                 /*
2032                         Send some initialization data
2033                 */
2034                 
2035                 // Send player info to all players
2036                 SendPlayerInfos();
2037
2038                 // Send inventory to player
2039                 UpdateCrafting(peer->id);
2040                 SendInventory(peer->id);
2041
2042                 // Send HP
2043                 {
2044                         Player *player = m_env.getPlayer(peer_id);
2045                         SendPlayerHP(player);
2046                 }
2047                 
2048                 // Send time of day
2049                 {
2050                         SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2051                                         m_env.getTimeOfDay());
2052                         m_con.Send(peer->id, 0, data, true);
2053                 }
2054                 
2055                 // Send information about server to player in chat
2056                 SendChatMessage(peer_id, getStatusString());
2057                 
2058                 // Send information about joining in chat
2059                 {
2060                         std::wstring name = L"unknown";
2061                         Player *player = m_env.getPlayer(peer_id);
2062                         if(player != NULL)
2063                                 name = narrow_to_wide(player->getName());
2064                         
2065                         std::wstring message;
2066                         message += L"*** ";
2067                         message += name;
2068                         message += L" joined game";
2069                         BroadcastChatMessage(message);
2070                 }
2071
2072                 return;
2073         }
2074
2075         if(peer_ser_ver == SER_FMT_VER_INVALID)
2076         {
2077                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
2078                                 " serialization format invalid or not initialized."
2079                                 " Skipping incoming command="<<command<<std::endl;
2080                 return;
2081         }
2082         
2083         Player *player = m_env.getPlayer(peer_id);
2084
2085         if(player == NULL){
2086                 derr_server<<"Server::ProcessData(): Cancelling: "
2087                                 "No player for peer_id="<<peer_id
2088                                 <<std::endl;
2089                 return;
2090         }
2091         if(command == TOSERVER_PLAYERPOS)
2092         {
2093                 if(datasize < 2+12+12+4+4)
2094                         return;
2095         
2096                 u32 start = 0;
2097                 v3s32 ps = readV3S32(&data[start+2]);
2098                 v3s32 ss = readV3S32(&data[start+2+12]);
2099                 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2100                 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2101                 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2102                 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2103                 pitch = wrapDegrees(pitch);
2104                 yaw = wrapDegrees(yaw);
2105                 player->setPosition(position);
2106                 player->setSpeed(speed);
2107                 player->setPitch(pitch);
2108                 player->setYaw(yaw);
2109                 
2110                 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2111                                 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2112                                 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2113         }
2114         else if(command == TOSERVER_GOTBLOCKS)
2115         {
2116                 if(datasize < 2+1)
2117                         return;
2118                 
2119                 /*
2120                         [0] u16 command
2121                         [2] u8 count
2122                         [3] v3s16 pos_0
2123                         [3+6] v3s16 pos_1
2124                         ...
2125                 */
2126
2127                 u16 count = data[2];
2128                 for(u16 i=0; i<count; i++)
2129                 {
2130                         if((s16)datasize < 2+1+(i+1)*6)
2131                                 throw con::InvalidIncomingDataException
2132                                         ("GOTBLOCKS length is too short");
2133                         v3s16 p = readV3S16(&data[2+1+i*6]);
2134                         /*dstream<<"Server: GOTBLOCKS ("
2135                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2136                         RemoteClient *client = getClient(peer_id);
2137                         client->GotBlock(p);
2138                 }
2139         }
2140         else if(command == TOSERVER_DELETEDBLOCKS)
2141         {
2142                 if(datasize < 2+1)
2143                         return;
2144                 
2145                 /*
2146                         [0] u16 command
2147                         [2] u8 count
2148                         [3] v3s16 pos_0
2149                         [3+6] v3s16 pos_1
2150                         ...
2151                 */
2152
2153                 u16 count = data[2];
2154                 for(u16 i=0; i<count; i++)
2155                 {
2156                         if((s16)datasize < 2+1+(i+1)*6)
2157                                 throw con::InvalidIncomingDataException
2158                                         ("DELETEDBLOCKS length is too short");
2159                         v3s16 p = readV3S16(&data[2+1+i*6]);
2160                         /*dstream<<"Server: DELETEDBLOCKS ("
2161                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2162                         RemoteClient *client = getClient(peer_id);
2163                         client->SetBlockNotSent(p);
2164                 }
2165         }
2166         else if(command == TOSERVER_CLICK_OBJECT)
2167         {
2168                 if(datasize < 13)
2169                         return;
2170
2171                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2172                         return;
2173
2174                 /*
2175                         [0] u16 command
2176                         [2] u8 button (0=left, 1=right)
2177                         [3] v3s16 block
2178                         [9] s16 id
2179                         [11] u16 item
2180                 */
2181                 u8 button = readU8(&data[2]);
2182                 v3s16 p;
2183                 p.X = readS16(&data[3]);
2184                 p.Y = readS16(&data[5]);
2185                 p.Z = readS16(&data[7]);
2186                 s16 id = readS16(&data[9]);
2187                 //u16 item_i = readU16(&data[11]);
2188
2189                 MapBlock *block = NULL;
2190                 try
2191                 {
2192                         block = m_env.getMap().getBlockNoCreate(p);
2193                 }
2194                 catch(InvalidPositionException &e)
2195                 {
2196                         derr_server<<"CLICK_OBJECT block not found"<<std::endl;
2197                         return;
2198                 }
2199
2200                 MapBlockObject *obj = block->getObject(id);
2201
2202                 if(obj == NULL)
2203                 {
2204                         derr_server<<"CLICK_OBJECT object not found"<<std::endl;
2205                         return;
2206                 }
2207
2208                 //TODO: Check that object is reasonably close
2209                 
2210                 // Left click
2211                 if(button == 0)
2212                 {
2213                         InventoryList *ilist = player->inventory.getList("main");
2214                         if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2215                         {
2216                         
2217                                 // Skip if inventory has no free space
2218                                 if(ilist->getUsedSlots() == ilist->getSize())
2219                                 {
2220                                         dout_server<<"Player inventory has no free space"<<std::endl;
2221                                         return;
2222                                 }
2223                                 
2224                                 /*
2225                                         Create the inventory item
2226                                 */
2227                                 InventoryItem *item = NULL;
2228                                 // If it is an item-object, take the item from it
2229                                 if(obj->getTypeId() == MAPBLOCKOBJECT_TYPE_ITEM)
2230                                 {
2231                                         item = ((ItemObject*)obj)->createInventoryItem();
2232                                 }
2233                                 // Else create an item of the object
2234                                 else
2235                                 {
2236                                         item = new MapBlockObjectItem
2237                                                         (obj->getInventoryString());
2238                                 }
2239                                 
2240                                 // Add to inventory and send inventory
2241                                 ilist->addItem(item);
2242                                 UpdateCrafting(player->peer_id);
2243                                 SendInventory(player->peer_id);
2244                         }
2245
2246                         // Remove from block
2247                         block->removeObject(id);
2248                 }
2249         }
2250         else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2251         {
2252                 if(datasize < 7)
2253                         return;
2254
2255                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2256                         return;
2257
2258                 /*
2259                         length: 7
2260                         [0] u16 command
2261                         [2] u8 button (0=left, 1=right)
2262                         [3] u16 id
2263                         [5] u16 item
2264                 */
2265                 u8 button = readU8(&data[2]);
2266                 u16 id = readS16(&data[3]);
2267                 u16 item_i = readU16(&data[11]);
2268         
2269                 ServerActiveObject *obj = m_env.getActiveObject(id);
2270
2271                 if(obj == NULL)
2272                 {
2273                         derr_server<<"Server: CLICK_ACTIVEOBJECT: object not found"
2274                                         <<std::endl;
2275                         return;
2276                 }
2277
2278                 //TODO: Check that object is reasonably close
2279                 
2280                 // Left click, pick object up (usually)
2281                 if(button == 0)
2282                 {
2283                         InventoryList *ilist = player->inventory.getList("main");
2284                         if(g_settings.getBool("creative_mode") == false && ilist != NULL)
2285                         {
2286                         
2287                                 // Skip if inventory has no free space
2288                                 if(ilist->getUsedSlots() == ilist->getSize())
2289                                 {
2290                                         dout_server<<"Player inventory has no free space"<<std::endl;
2291                                         return;
2292                                 }
2293
2294                                 // Skip if object has been removed
2295                                 if(obj->m_removed)
2296                                         return;
2297                                 
2298                                 /*
2299                                         Create the inventory item
2300                                 */
2301                                 InventoryItem *item = obj->createPickedUpItem();
2302                                 
2303                                 if(item)
2304                                 {
2305                                         // Add to inventory and send inventory
2306                                         ilist->addItem(item);
2307                                         UpdateCrafting(player->peer_id);
2308                                         SendInventory(player->peer_id);
2309
2310                                         // Remove object from environment
2311                                         obj->m_removed = true;
2312                                 }
2313                                 else
2314                                 {
2315                                         /*
2316                                                 Item cannot be picked up. Punch it instead.
2317                                         */
2318
2319                                         ToolItem *titem = NULL;
2320                                         std::string toolname = "";
2321
2322                                         InventoryList *mlist = player->inventory.getList("main");
2323                                         if(mlist != NULL)
2324                                         {
2325                                                 InventoryItem *item = mlist->getItem(item_i);
2326                                                 if(item && (std::string)item->getName() == "ToolItem")
2327                                                 {
2328                                                         titem = (ToolItem*)item;
2329                                                         toolname = titem->getToolName();
2330                                                 }
2331                                         }
2332                                         
2333                                         u16 wear = obj->punch(toolname);
2334                                         
2335                                         if(titem)
2336                                         {
2337                                                 bool weared_out = titem->addWear(wear);
2338                                                 if(weared_out)
2339                                                         mlist->deleteItem(item_i);
2340                                                 SendInventory(player->peer_id);
2341                                         }
2342                                 }
2343                         }
2344                 }
2345         }
2346         else if(command == TOSERVER_GROUND_ACTION)
2347         {
2348                 if(datasize < 17)
2349                         return;
2350                 /*
2351                         length: 17
2352                         [0] u16 command
2353                         [2] u8 action
2354                         [3] v3s16 nodepos_undersurface
2355                         [9] v3s16 nodepos_abovesurface
2356                         [15] u16 item
2357                         actions:
2358                         0: start digging
2359                         1: place block
2360                         2: stop digging (all parameters ignored)
2361                         3: digging completed
2362                 */
2363                 u8 action = readU8(&data[2]);
2364                 v3s16 p_under;
2365                 p_under.X = readS16(&data[3]);
2366                 p_under.Y = readS16(&data[5]);
2367                 p_under.Z = readS16(&data[7]);
2368                 v3s16 p_over;
2369                 p_over.X = readS16(&data[9]);
2370                 p_over.Y = readS16(&data[11]);
2371                 p_over.Z = readS16(&data[13]);
2372                 u16 item_i = readU16(&data[15]);
2373
2374                 //TODO: Check that target is reasonably close
2375                 
2376                 /*
2377                         0: start digging
2378                 */
2379                 if(action == 0)
2380                 {
2381                         /*
2382                                 NOTE: This can be used in the future to check if
2383                                 somebody is cheating, by checking the timing.
2384                         */
2385                 } // action == 0
2386
2387                 /*
2388                         2: stop digging
2389                 */
2390                 else if(action == 2)
2391                 {
2392 #if 0
2393                         RemoteClient *client = getClient(peer->id);
2394                         JMutexAutoLock digmutex(client->m_dig_mutex);
2395                         client->m_dig_tool_item = -1;
2396 #endif
2397                 }
2398
2399                 /*
2400                         3: Digging completed
2401                 */
2402                 else if(action == 3)
2403                 {
2404                         // Mandatory parameter; actually used for nothing
2405                         core::map<v3s16, MapBlock*> modified_blocks;
2406
2407                         u8 material = CONTENT_IGNORE;
2408                         u8 mineral = MINERAL_NONE;
2409
2410                         bool cannot_remove_node = false;
2411
2412                         try
2413                         {
2414                                 MapNode n = m_env.getMap().getNode(p_under);
2415                                 // Get mineral
2416                                 mineral = n.getMineral();
2417                                 // Get material at position
2418                                 material = n.d;
2419                                 // If not yet cancelled
2420                                 if(cannot_remove_node == false)
2421                                 {
2422                                         // If it's not diggable, do nothing
2423                                         if(content_diggable(material) == false)
2424                                         {
2425                                                 derr_server<<"Server: Not finishing digging: "
2426                                                                 <<"Node not diggable"
2427                                                                 <<std::endl;
2428                                                 cannot_remove_node = true;
2429                                         }
2430                                 }
2431                                 // If not yet cancelled
2432                                 if(cannot_remove_node == false)
2433                                 {
2434                                         // Get node metadata
2435                                         NodeMetadata *meta = m_env.getMap().getNodeMetadata(p_under);
2436                                         if(meta && meta->nodeRemovalDisabled() == true)
2437                                         {
2438                                                 derr_server<<"Server: Not finishing digging: "
2439                                                                 <<"Node metadata disables removal"
2440                                                                 <<std::endl;
2441                                                 cannot_remove_node = true;
2442                                         }
2443                                 }
2444                         }
2445                         catch(InvalidPositionException &e)
2446                         {
2447                                 derr_server<<"Server: Not finishing digging: Node not found."
2448                                                 <<" Adding block to emerge queue."
2449                                                 <<std::endl;
2450                                 m_emerge_queue.addBlock(peer_id,
2451                                                 getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2452                                 cannot_remove_node = true;
2453                         }
2454
2455                         // Make sure the player is allowed to do it
2456                         if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2457                         {
2458                                 dstream<<"Player "<<player->getName()<<" cannot remove node"
2459                                                 <<" because privileges are "<<getPlayerPrivs(player)
2460                                                 <<std::endl;
2461                                 cannot_remove_node = true;
2462                         }
2463
2464                         /*
2465                                 If node can't be removed, set block to be re-sent to
2466                                 client and quit.
2467                         */
2468                         if(cannot_remove_node)
2469                         {
2470                                 derr_server<<"Server: Not finishing digging."<<std::endl;
2471
2472                                 // Client probably has wrong data.
2473                                 // Set block not sent, so that client will get
2474                                 // a valid one.
2475                                 dstream<<"Client "<<peer_id<<" tried to dig "
2476                                                 <<"node; but node cannot be removed."
2477                                                 <<" setting MapBlock not sent."<<std::endl;
2478                                 RemoteClient *client = getClient(peer_id);
2479                                 v3s16 blockpos = getNodeBlockPos(p_under);
2480                                 client->SetBlockNotSent(blockpos);
2481                                         
2482                                 return;
2483                         }
2484                         
2485                         /*
2486                                 Send the removal to all other clients.
2487                                 - If other player is close, send REMOVENODE
2488                                 - Otherwise set blocks not sent
2489                         */
2490                         core::list<u16> far_players;
2491                         sendRemoveNode(p_under, peer_id, &far_players, 100);
2492                         
2493                         /*
2494                                 Update and send inventory
2495                         */
2496
2497                         if(g_settings.getBool("creative_mode") == false)
2498                         {
2499                                 /*
2500                                         Wear out tool
2501                                 */
2502                                 InventoryList *mlist = player->inventory.getList("main");
2503                                 if(mlist != NULL)
2504                                 {
2505                                         InventoryItem *item = mlist->getItem(item_i);
2506                                         if(item && (std::string)item->getName() == "ToolItem")
2507                                         {
2508                                                 ToolItem *titem = (ToolItem*)item;
2509                                                 std::string toolname = titem->getToolName();
2510
2511                                                 // Get digging properties for material and tool
2512                                                 DiggingProperties prop =
2513                                                                 getDiggingProperties(material, toolname);
2514
2515                                                 if(prop.diggable == false)
2516                                                 {
2517                                                         derr_server<<"Server: WARNING: Player digged"
2518                                                                         <<" with impossible material + tool"
2519                                                                         <<" combination"<<std::endl;
2520                                                 }
2521                                                 
2522                                                 bool weared_out = titem->addWear(prop.wear);
2523
2524                                                 if(weared_out)
2525                                                 {
2526                                                         mlist->deleteItem(item_i);
2527                                                 }
2528                                         }
2529                                 }
2530
2531                                 /*
2532                                         Add dug item to inventory
2533                                 */
2534
2535                                 InventoryItem *item = NULL;
2536
2537                                 if(mineral != MINERAL_NONE)
2538                                         item = getDiggedMineralItem(mineral);
2539                                 
2540                                 // If not mineral
2541                                 if(item == NULL)
2542                                 {
2543                                         std::string &dug_s = content_features(material).dug_item;
2544                                         if(dug_s != "")
2545                                         {
2546                                                 std::istringstream is(dug_s, std::ios::binary);
2547                                                 item = InventoryItem::deSerialize(is);
2548                                         }
2549                                 }
2550                                 
2551                                 if(item != NULL)
2552                                 {
2553                                         // Add a item to inventory
2554                                         player->inventory.addItem("main", item);
2555
2556                                         // Send inventory
2557                                         UpdateCrafting(player->peer_id);
2558                                         SendInventory(player->peer_id);
2559                                 }
2560                         }
2561
2562                         /*
2563                                 Remove the node
2564                                 (this takes some time so it is done after the quick stuff)
2565                         */
2566                         m_ignore_map_edit_events = true;
2567                         m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2568                         m_ignore_map_edit_events = false;
2569                         
2570                         /*
2571                                 Set blocks not sent to far players
2572                         */
2573                         for(core::list<u16>::Iterator
2574                                         i = far_players.begin();
2575                                         i != far_players.end(); i++)
2576                         {
2577                                 u16 peer_id = *i;
2578                                 RemoteClient *client = getClient(peer_id);
2579                                 if(client==NULL)
2580                                         continue;
2581                                 client->SetBlocksNotSent(modified_blocks);
2582                         }
2583                 }
2584                 
2585                 /*
2586                         1: place block
2587                 */
2588                 else if(action == 1)
2589                 {
2590
2591                         InventoryList *ilist = player->inventory.getList("main");
2592                         if(ilist == NULL)
2593                                 return;
2594
2595                         // Get item
2596                         InventoryItem *item = ilist->getItem(item_i);
2597                         
2598                         // If there is no item, it is not possible to add it anywhere
2599                         if(item == NULL)
2600                                 return;
2601                         
2602                         /*
2603                                 Handle material items
2604                         */
2605                         if(std::string("MaterialItem") == item->getName())
2606                         {
2607                                 try{
2608                                         // Don't add a node if this is not a free space
2609                                         MapNode n2 = m_env.getMap().getNode(p_over);
2610                                         bool no_enough_privs =
2611                                                         ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2612                                         if(no_enough_privs)
2613                                                 dstream<<"Player "<<player->getName()<<" cannot add node"
2614                                                         <<" because privileges are "<<getPlayerPrivs(player)
2615                                                         <<std::endl;
2616
2617                                         if(content_buildable_to(n2.d) == false
2618                                                 || no_enough_privs)
2619                                         {
2620                                                 // Client probably has wrong data.
2621                                                 // Set block not sent, so that client will get
2622                                                 // a valid one.
2623                                                 dstream<<"Client "<<peer_id<<" tried to place"
2624                                                                 <<" node in invalid position; setting"
2625                                                                 <<" MapBlock not sent."<<std::endl;
2626                                                 RemoteClient *client = getClient(peer_id);
2627                                                 v3s16 blockpos = getNodeBlockPos(p_over);
2628                                                 client->SetBlockNotSent(blockpos);
2629                                                 return;
2630                                         }
2631                                 }
2632                                 catch(InvalidPositionException &e)
2633                                 {
2634                                         derr_server<<"Server: Ignoring ADDNODE: Node not found"
2635                                                         <<" Adding block to emerge queue."
2636                                                         <<std::endl;
2637                                         m_emerge_queue.addBlock(peer_id,
2638                                                         getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2639                                         return;
2640                                 }
2641
2642                                 // Reset build time counter
2643                                 getClient(peer->id)->m_time_from_building = 0.0;
2644                                 
2645                                 // Create node data
2646                                 MaterialItem *mitem = (MaterialItem*)item;
2647                                 MapNode n;
2648                                 n.d = mitem->getMaterial();
2649                                 if(content_features(n.d).wall_mounted)
2650                                         n.dir = packDir(p_under - p_over);
2651                                 
2652                                 /*
2653                                         Send to all players
2654                                 */
2655                                 core::list<u16> far_players;
2656                                 sendAddNode(p_over, n, 0, &far_players, 100);
2657                                 
2658                                 /*
2659                                         Handle inventory
2660                                 */
2661                                 InventoryList *ilist = player->inventory.getList("main");
2662                                 if(g_settings.getBool("creative_mode") == false && ilist)
2663                                 {
2664                                         // Remove from inventory and send inventory
2665                                         if(mitem->getCount() == 1)
2666                                                 ilist->deleteItem(item_i);
2667                                         else
2668                                                 mitem->remove(1);
2669                                         // Send inventory
2670                                         UpdateCrafting(peer_id);
2671                                         SendInventory(peer_id);
2672                                 }
2673                                 
2674                                 /*
2675                                         Add node.
2676
2677                                         This takes some time so it is done after the quick stuff
2678                                 */
2679                                 core::map<v3s16, MapBlock*> modified_blocks;
2680                                 m_ignore_map_edit_events = true;
2681                                 m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
2682                                 m_ignore_map_edit_events = false;
2683                                 
2684                                 /*
2685                                         Set blocks not sent to far players
2686                                 */
2687                                 for(core::list<u16>::Iterator
2688                                                 i = far_players.begin();
2689                                                 i != far_players.end(); i++)
2690                                 {
2691                                         u16 peer_id = *i;
2692                                         RemoteClient *client = getClient(peer_id);
2693                                         if(client==NULL)
2694                                                 continue;
2695                                         client->SetBlocksNotSent(modified_blocks);
2696                                 }
2697
2698                                 /*
2699                                         Calculate special events
2700                                 */
2701                                 
2702                                 /*if(n.d == CONTENT_MESE)
2703                                 {
2704                                         u32 count = 0;
2705                                         for(s16 z=-1; z<=1; z++)
2706                                         for(s16 y=-1; y<=1; y++)
2707                                         for(s16 x=-1; x<=1; x++)
2708                                         {
2709                                                 
2710                                         }
2711                                 }*/
2712                         }
2713                         /*
2714                                 Place other item (not a block)
2715                         */
2716                         else
2717                         {
2718                                 v3s16 blockpos = getNodeBlockPos(p_over);
2719                                 
2720                                 /*
2721                                         Check that the block is loaded so that the item
2722                                         can properly be added to the static list too
2723                                 */
2724                                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2725                                 if(block==NULL)
2726                                 {
2727                                         derr_server<<"Error while placing object: "
2728                                                         "block not found"<<std::endl;
2729                                         return;
2730                                 }
2731
2732                                 dout_server<<"Placing a miscellaneous item on map"
2733                                                 <<std::endl;
2734                                 
2735                                 // Calculate a position for it
2736                                 v3f pos = intToFloat(p_over, BS);
2737                                 //pos.Y -= BS*0.45;
2738                                 pos.Y -= BS*0.25; // let it drop a bit
2739                                 // Randomize a bit
2740                                 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2741                                 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2742
2743                                 /*
2744                                         Create the object
2745                                 */
2746                                 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
2747
2748                                 if(obj == NULL)
2749                                 {
2750                                         derr_server<<"WARNING: item resulted in NULL object, "
2751                                                         <<"not placing onto map"
2752                                                         <<std::endl;
2753                                 }
2754                                 else
2755                                 {
2756                                         // Add the object to the environment
2757                                         m_env.addActiveObject(obj);
2758                                         
2759                                         dout_server<<"Placed object"<<std::endl;
2760
2761                                         if(g_settings.getBool("creative_mode") == false)
2762                                         {
2763                                                 // Delete the right amount of items from the slot
2764                                                 u16 dropcount = item->getDropCount();
2765                                                 
2766                                                 // Delete item if all gone
2767                                                 if(item->getCount() <= dropcount)
2768                                                 {
2769                                                         if(item->getCount() < dropcount)
2770                                                                 dstream<<"WARNING: Server: dropped more items"
2771                                                                                 <<" than the slot contains"<<std::endl;
2772                                                         
2773                                                         InventoryList *ilist = player->inventory.getList("main");
2774                                                         if(ilist)
2775                                                                 // Remove from inventory and send inventory
2776                                                                 ilist->deleteItem(item_i);
2777                                                 }
2778                                                 // Else decrement it
2779                                                 else
2780                                                         item->remove(dropcount);
2781                                                 
2782                                                 // Send inventory
2783                                                 UpdateCrafting(peer_id);
2784                                                 SendInventory(peer_id);
2785                                         }
2786                                 }
2787                         }
2788
2789                 } // action == 1
2790
2791                 /*
2792                         Catch invalid actions
2793                 */
2794                 else
2795                 {
2796                         derr_server<<"WARNING: Server: Invalid action "
2797                                         <<action<<std::endl;
2798                 }
2799         }
2800 #if 0
2801         else if(command == TOSERVER_RELEASE)
2802         {
2803                 if(datasize < 3)
2804                         return;
2805                 /*
2806                         length: 3
2807                         [0] u16 command
2808                         [2] u8 button
2809                 */
2810                 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
2811         }
2812 #endif
2813         else if(command == TOSERVER_SIGNTEXT)
2814         {
2815                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2816                         return;
2817                 /*
2818                         u16 command
2819                         v3s16 blockpos
2820                         s16 id
2821                         u16 textlen
2822                         textdata
2823                 */
2824                 std::string datastring((char*)&data[2], datasize-2);
2825                 std::istringstream is(datastring, std::ios_base::binary);
2826                 u8 buf[6];
2827                 // Read stuff
2828                 is.read((char*)buf, 6);
2829                 v3s16 blockpos = readV3S16(buf);
2830                 is.read((char*)buf, 2);
2831                 s16 id = readS16(buf);
2832                 is.read((char*)buf, 2);
2833                 u16 textlen = readU16(buf);
2834                 std::string text;
2835                 for(u16 i=0; i<textlen; i++)
2836                 {
2837                         is.read((char*)buf, 1);
2838                         text += (char)buf[0];
2839                 }
2840
2841                 MapBlock *block = NULL;
2842                 try
2843                 {
2844                         block = m_env.getMap().getBlockNoCreate(blockpos);
2845                 }
2846                 catch(InvalidPositionException &e)
2847                 {
2848                         derr_server<<"Error while setting sign text: "
2849                                         "block not found"<<std::endl;
2850                         return;
2851                 }
2852
2853                 MapBlockObject *obj = block->getObject(id);
2854                 if(obj == NULL)
2855                 {
2856                         derr_server<<"Error while setting sign text: "
2857                                         "object not found"<<std::endl;
2858                         return;
2859                 }
2860                 
2861                 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
2862                 {
2863                         derr_server<<"Error while setting sign text: "
2864                                         "object is not a sign"<<std::endl;
2865                         return;
2866                 }
2867
2868                 ((SignObject*)obj)->setText(text);
2869
2870                 obj->getBlock()->setChangedFlag();
2871         }
2872         else if(command == TOSERVER_SIGNNODETEXT)
2873         {
2874                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
2875                         return;
2876                 /*
2877                         u16 command
2878                         v3s16 p
2879                         u16 textlen
2880                         textdata
2881                 */
2882                 std::string datastring((char*)&data[2], datasize-2);
2883                 std::istringstream is(datastring, std::ios_base::binary);
2884                 u8 buf[6];
2885                 // Read stuff
2886                 is.read((char*)buf, 6);
2887                 v3s16 p = readV3S16(buf);
2888                 is.read((char*)buf, 2);
2889                 u16 textlen = readU16(buf);
2890                 std::string text;
2891                 for(u16 i=0; i<textlen; i++)
2892                 {
2893                         is.read((char*)buf, 1);
2894                         text += (char)buf[0];
2895                 }
2896
2897                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
2898                 if(!meta)
2899                         return;
2900                 if(meta->typeId() != CONTENT_SIGN_WALL)
2901                         return;
2902                 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
2903                 signmeta->setText(text);
2904                 
2905                 v3s16 blockpos = getNodeBlockPos(p);
2906                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2907                 if(block)
2908                 {
2909                         block->setChangedFlag();
2910                 }
2911
2912                 for(core::map<u16, RemoteClient*>::Iterator
2913                         i = m_clients.getIterator();
2914                         i.atEnd()==false; i++)
2915                 {
2916                         RemoteClient *client = i.getNode()->getValue();
2917                         client->SetBlockNotSent(blockpos);
2918                 }
2919         }
2920         else if(command == TOSERVER_INVENTORY_ACTION)
2921         {
2922                 /*// Ignore inventory changes if in creative mode
2923                 if(g_settings.getBool("creative_mode") == true)
2924                 {
2925                         dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
2926                                         <<std::endl;
2927                         return;
2928                 }*/
2929                 // Strip command and create a stream
2930                 std::string datastring((char*)&data[2], datasize-2);
2931                 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2932                 std::istringstream is(datastring, std::ios_base::binary);
2933                 // Create an action
2934                 InventoryAction *a = InventoryAction::deSerialize(is);
2935                 if(a != NULL)
2936                 {
2937                         // Create context
2938                         InventoryContext c;
2939                         c.current_player = player;
2940
2941                         /*
2942                                 Handle craftresult specially if not in creative mode
2943                         */
2944                         bool disable_action = false;
2945                         if(a->getType() == IACTION_MOVE
2946                                         && g_settings.getBool("creative_mode") == false)
2947                         {
2948                                 IMoveAction *ma = (IMoveAction*)a;
2949                                 if(ma->to_inv == "current_player" &&
2950                                                 ma->from_inv == "current_player")
2951                                 {
2952                                         InventoryList *rlist = player->inventory.getList("craftresult");
2953                                         assert(rlist);
2954                                         InventoryList *clist = player->inventory.getList("craft");
2955                                         assert(clist);
2956                                         InventoryList *mlist = player->inventory.getList("main");
2957                                         assert(mlist);
2958                                         /*
2959                                                 Craftresult is no longer preview if something
2960                                                 is moved into it
2961                                         */
2962                                         if(ma->to_list == "craftresult"
2963                                                         && ma->from_list != "craftresult")
2964                                         {
2965                                                 // If it currently is a preview, remove
2966                                                 // its contents
2967                                                 if(player->craftresult_is_preview)
2968                                                 {
2969                                                         rlist->deleteItem(0);
2970                                                 }
2971                                                 player->craftresult_is_preview = false;
2972                                         }
2973                                         /*
2974                                                 Crafting takes place if this condition is true.
2975                                         */
2976                                         if(player->craftresult_is_preview &&
2977                                                         ma->from_list == "craftresult")
2978                                         {
2979                                                 player->craftresult_is_preview = false;
2980                                                 clist->decrementMaterials(1);
2981                                         }
2982                                         /*
2983                                                 If the craftresult is placed on itself, move it to
2984                                                 main inventory instead of doing the action
2985                                         */
2986                                         if(ma->to_list == "craftresult"
2987                                                         && ma->from_list == "craftresult")
2988                                         {
2989                                                 disable_action = true;
2990                                                 
2991                                                 InventoryItem *item1 = rlist->changeItem(0, NULL);
2992                                                 mlist->addItem(item1);
2993                                         }
2994                                 }
2995                         }
2996                         
2997                         if(disable_action == false)
2998                         {
2999                                 // Feed action to player inventory
3000                                 a->apply(&c, this);
3001                                 // Eat the action
3002                                 delete a;
3003                         }
3004                         else
3005                         {
3006                                 // Send inventory
3007                                 UpdateCrafting(player->peer_id);
3008                                 SendInventory(player->peer_id);
3009                         }
3010                 }
3011                 else
3012                 {
3013                         dstream<<"TOSERVER_INVENTORY_ACTION: "
3014                                         <<"InventoryAction::deSerialize() returned NULL"
3015                                         <<std::endl;
3016                 }
3017         }
3018         else if(command == TOSERVER_CHAT_MESSAGE)
3019         {
3020                 /*
3021                         u16 command
3022                         u16 length
3023                         wstring message
3024                 */
3025                 u8 buf[6];
3026                 std::string datastring((char*)&data[2], datasize-2);
3027                 std::istringstream is(datastring, std::ios_base::binary);
3028                 
3029                 // Read stuff
3030                 is.read((char*)buf, 2);
3031                 u16 len = readU16(buf);
3032                 
3033                 std::wstring message;
3034                 for(u16 i=0; i<len; i++)
3035                 {
3036                         is.read((char*)buf, 2);
3037                         message += (wchar_t)readU16(buf);
3038                 }
3039
3040                 // Get player name of this client
3041                 std::wstring name = narrow_to_wide(player->getName());
3042                 
3043                 // Line to send to players
3044                 std::wstring line;
3045                 // Whether to send to the player that sent the line
3046                 bool send_to_sender = false;
3047                 // Whether to send to other players
3048                 bool send_to_others = false;
3049                 
3050                 // Local player gets all privileges regardless of
3051                 // what's set on their account.
3052                 u64 privs = getPlayerPrivs(player);
3053
3054                 // Parse commands
3055                 std::wstring commandprefix = L"/#";
3056                 if(message.substr(0, commandprefix.size()) == commandprefix)
3057                 {
3058                         line += L"Server: ";
3059
3060                         message = message.substr(commandprefix.size());
3061
3062                         ServerCommandContext *ctx = new ServerCommandContext(
3063                                 str_split(message, L' '),
3064                                 this,
3065                                 &m_env,
3066                                 player,
3067                                 privs);
3068
3069                         line += processServerCommand(ctx);
3070                         send_to_sender = ctx->flags & 1;
3071                         send_to_others = ctx->flags & 2;
3072                         delete ctx;
3073
3074                 }
3075                 else
3076                 {
3077                         if(privs & PRIV_SHOUT)
3078                         {
3079                                 line += L"<";
3080                                 line += name;
3081                                 line += L"> ";
3082                                 line += message;
3083                                 send_to_others = true;
3084                         }
3085                         else
3086                         {
3087                                 line += L"Server: You are not allowed to shout";
3088                                 send_to_sender = true;
3089                         }
3090                 }
3091                 
3092                 if(line != L"")
3093                 {
3094                         dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3095
3096                         /*
3097                                 Send the message to clients
3098                         */
3099                         for(core::map<u16, RemoteClient*>::Iterator
3100                                 i = m_clients.getIterator();
3101                                 i.atEnd() == false; i++)
3102                         {
3103                                 // Get client and check that it is valid
3104                                 RemoteClient *client = i.getNode()->getValue();
3105                                 assert(client->peer_id == i.getNode()->getKey());
3106                                 if(client->serialization_version == SER_FMT_VER_INVALID)
3107                                         continue;
3108
3109                                 // Filter recipient
3110                                 bool sender_selected = (peer_id == client->peer_id);
3111                                 if(sender_selected == true && send_to_sender == false)
3112                                         continue;
3113                                 if(sender_selected == false && send_to_others == false)
3114                                         continue;
3115
3116                                 SendChatMessage(client->peer_id, line);
3117                         }
3118                 }
3119         }
3120         else if(command == TOSERVER_DAMAGE)
3121         {
3122                 if(g_settings.getBool("enable_damage"))
3123                 {
3124                         std::string datastring((char*)&data[2], datasize-2);
3125                         std::istringstream is(datastring, std::ios_base::binary);
3126                         u8 damage = readU8(is);
3127                         if(player->hp > damage)
3128                         {
3129                                 player->hp -= damage;
3130                         }
3131                         else
3132                         {
3133                                 player->hp = 0;
3134
3135                                 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3136                                                 <<std::endl;
3137                                 
3138                                 v3f pos = findSpawnPos(m_env.getServerMap());
3139                                 player->setPosition(pos);
3140                                 player->hp = 20;
3141                                 SendMovePlayer(player);
3142                                 SendPlayerHP(player);
3143                                 
3144                                 //TODO: Throw items around
3145                         }
3146                 }
3147
3148                 SendPlayerHP(player);
3149         }
3150         else if(command == TOSERVER_PASSWORD)
3151         {
3152                 /*
3153                         [0] u16 TOSERVER_PASSWORD
3154                         [2] u8[28] old password
3155                         [30] u8[28] new password
3156                 */
3157
3158                 if(datasize != 2+PASSWORD_SIZE*2)
3159                         return;
3160                 /*char password[PASSWORD_SIZE];
3161                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3162                         password[i] = data[2+i];
3163                 password[PASSWORD_SIZE-1] = 0;*/
3164                 std::string oldpwd;
3165                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3166                 {
3167                         char c = data[2+i];
3168                         if(c == 0)
3169                                 break;
3170                         oldpwd += c;
3171                 }
3172                 std::string newpwd;
3173                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3174                 {
3175                         char c = data[2+PASSWORD_SIZE+i];
3176                         if(c == 0)
3177                                 break;
3178                         newpwd += c;
3179                 }
3180
3181                 std::string playername = player->getName();
3182
3183                 if(m_authmanager.exists(playername) == false)
3184                 {
3185                         dstream<<"Server: playername not found in authmanager"<<std::endl;
3186                         // Wrong old password supplied!!
3187                         SendChatMessage(peer_id, L"playername not found in authmanager");
3188                         return;
3189                 }
3190
3191                 std::string checkpwd = m_authmanager.getPassword(playername);
3192                 
3193                 if(oldpwd != checkpwd)
3194                 {
3195                         dstream<<"Server: invalid old password"<<std::endl;
3196                         // Wrong old password supplied!!
3197                         SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3198                         return;
3199                 }
3200
3201                 m_authmanager.setPassword(playername, newpwd);
3202                 
3203                 dstream<<"Server: password change successful for "<<playername
3204                                 <<std::endl;
3205                 SendChatMessage(peer_id, L"Password change successful");
3206         }
3207         else
3208         {
3209                 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3210                                 "unknown command "<<command<<std::endl;
3211         }
3212         
3213         } //try
3214         catch(SendFailedException &e)
3215         {
3216                 derr_server<<"Server::ProcessData(): SendFailedException: "
3217                                 <<"what="<<e.what()
3218                                 <<std::endl;
3219         }
3220 }
3221
3222 void Server::onMapEditEvent(MapEditEvent *event)
3223 {
3224         dstream<<"Server::onMapEditEvent()"<<std::endl;
3225         if(m_ignore_map_edit_events)
3226                 return;
3227         MapEditEvent *e = event->clone();
3228         m_unsent_map_edit_queue.push_back(e);
3229 }
3230
3231 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3232 {
3233         if(id == "current_player")
3234         {
3235                 assert(c->current_player);
3236                 return &(c->current_player->inventory);
3237         }
3238         
3239         Strfnd fn(id);
3240         std::string id0 = fn.next(":");
3241
3242         if(id0 == "nodemeta")
3243         {
3244                 v3s16 p;
3245                 p.X = stoi(fn.next(","));
3246                 p.Y = stoi(fn.next(","));
3247                 p.Z = stoi(fn.next(","));
3248                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3249                 if(meta)
3250                         return meta->getInventory();
3251                 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3252                                 <<"no metadata found"<<std::endl;
3253                 return NULL;
3254         }
3255
3256         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3257         return NULL;
3258 }
3259 void Server::inventoryModified(InventoryContext *c, std::string id)
3260 {
3261         if(id == "current_player")
3262         {
3263                 assert(c->current_player);
3264                 // Send inventory
3265                 UpdateCrafting(c->current_player->peer_id);
3266                 SendInventory(c->current_player->peer_id);
3267                 return;
3268         }
3269         
3270         Strfnd fn(id);
3271         std::string id0 = fn.next(":");
3272
3273         if(id0 == "nodemeta")
3274         {
3275                 v3s16 p;
3276                 p.X = stoi(fn.next(","));
3277                 p.Y = stoi(fn.next(","));
3278                 p.Z = stoi(fn.next(","));
3279                 v3s16 blockpos = getNodeBlockPos(p);
3280
3281                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3282                 if(meta)
3283                         meta->inventoryModified();
3284
3285                 for(core::map<u16, RemoteClient*>::Iterator
3286                         i = m_clients.getIterator();
3287                         i.atEnd()==false; i++)
3288                 {
3289                         RemoteClient *client = i.getNode()->getValue();
3290                         client->SetBlockNotSent(blockpos);
3291                 }
3292
3293                 return;
3294         }
3295
3296         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3297 }
3298
3299 core::list<PlayerInfo> Server::getPlayerInfo()
3300 {
3301         DSTACK(__FUNCTION_NAME);
3302         JMutexAutoLock envlock(m_env_mutex);
3303         JMutexAutoLock conlock(m_con_mutex);
3304         
3305         core::list<PlayerInfo> list;
3306
3307         core::list<Player*> players = m_env.getPlayers();
3308         
3309         core::list<Player*>::Iterator i;
3310         for(i = players.begin();
3311                         i != players.end(); i++)
3312         {
3313                 PlayerInfo info;
3314
3315                 Player *player = *i;
3316
3317                 try{
3318                         con::Peer *peer = m_con.GetPeer(player->peer_id);
3319                         // Copy info from peer to info struct
3320                         info.id = peer->id;
3321                         info.address = peer->address;
3322                         info.avg_rtt = peer->avg_rtt;
3323                 }
3324                 catch(con::PeerNotFoundException &e)
3325                 {
3326                         // Set dummy peer info
3327                         info.id = 0;
3328                         info.address = Address(0,0,0,0,0);
3329                         info.avg_rtt = 0.0;
3330                 }
3331
3332                 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3333                 info.position = player->getPosition();
3334
3335                 list.push_back(info);
3336         }
3337
3338         return list;
3339 }
3340
3341
3342 void Server::peerAdded(con::Peer *peer)
3343 {
3344         DSTACK(__FUNCTION_NAME);
3345         dout_server<<"Server::peerAdded(): peer->id="
3346                         <<peer->id<<std::endl;
3347         
3348         PeerChange c;
3349         c.type = PEER_ADDED;
3350         c.peer_id = peer->id;
3351         c.timeout = false;
3352         m_peer_change_queue.push_back(c);
3353 }
3354
3355 void Server::deletingPeer(con::Peer *peer, bool timeout)
3356 {
3357         DSTACK(__FUNCTION_NAME);
3358         dout_server<<"Server::deletingPeer(): peer->id="
3359                         <<peer->id<<", timeout="<<timeout<<std::endl;
3360         
3361         PeerChange c;
3362         c.type = PEER_REMOVED;
3363         c.peer_id = peer->id;
3364         c.timeout = timeout;
3365         m_peer_change_queue.push_back(c);
3366 }
3367
3368 /*
3369         Static send methods
3370 */
3371
3372 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3373 {
3374         DSTACK(__FUNCTION_NAME);
3375         std::ostringstream os(std::ios_base::binary);
3376
3377         writeU16(os, TOCLIENT_HP);
3378         writeU8(os, hp);
3379
3380         // Make data buffer
3381         std::string s = os.str();
3382         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3383         // Send as reliable
3384         con.Send(peer_id, 0, data, true);
3385 }
3386
3387 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3388                 const std::wstring &reason)
3389 {
3390         DSTACK(__FUNCTION_NAME);
3391         std::ostringstream os(std::ios_base::binary);
3392
3393         writeU16(os, TOCLIENT_ACCESS_DENIED);
3394         os<<serializeWideString(reason);
3395
3396         // Make data buffer
3397         std::string s = os.str();
3398         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3399         // Send as reliable
3400         con.Send(peer_id, 0, data, true);
3401 }
3402
3403 /*
3404         Non-static send methods
3405 */
3406
3407 void Server::SendObjectData(float dtime)
3408 {
3409         DSTACK(__FUNCTION_NAME);
3410
3411         core::map<v3s16, bool> stepped_blocks;
3412         
3413         for(core::map<u16, RemoteClient*>::Iterator
3414                 i = m_clients.getIterator();
3415                 i.atEnd() == false; i++)
3416         {
3417                 u16 peer_id = i.getNode()->getKey();
3418                 RemoteClient *client = i.getNode()->getValue();
3419                 assert(client->peer_id == peer_id);
3420                 
3421                 if(client->serialization_version == SER_FMT_VER_INVALID)
3422                         continue;
3423                 
3424                 client->SendObjectData(this, dtime, stepped_blocks);
3425         }
3426 }
3427
3428 void Server::SendPlayerInfos()
3429 {
3430         DSTACK(__FUNCTION_NAME);
3431
3432         //JMutexAutoLock envlock(m_env_mutex);
3433         
3434         // Get connected players
3435         core::list<Player*> players = m_env.getPlayers(true);
3436         
3437         u32 player_count = players.getSize();
3438         u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3439
3440         SharedBuffer<u8> data(datasize);
3441         writeU16(&data[0], TOCLIENT_PLAYERINFO);
3442         
3443         u32 start = 2;
3444         core::list<Player*>::Iterator i;
3445         for(i = players.begin();
3446                         i != players.end(); i++)
3447         {
3448                 Player *player = *i;
3449
3450                 /*dstream<<"Server sending player info for player with "
3451                                 "peer_id="<<player->peer_id<<std::endl;*/
3452                 
3453                 writeU16(&data[start], player->peer_id);
3454                 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3455                 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3456                 start += 2+PLAYERNAME_SIZE;
3457         }
3458
3459         //JMutexAutoLock conlock(m_con_mutex);
3460
3461         // Send as reliable
3462         m_con.SendToAll(0, data, true);
3463 }
3464
3465 void Server::SendInventory(u16 peer_id)
3466 {
3467         DSTACK(__FUNCTION_NAME);
3468         
3469         Player* player = m_env.getPlayer(peer_id);
3470         assert(player);
3471
3472         /*
3473                 Serialize it
3474         */
3475
3476         std::ostringstream os;
3477         //os.imbue(std::locale("C"));
3478
3479         player->inventory.serialize(os);
3480
3481         std::string s = os.str();
3482         
3483         SharedBuffer<u8> data(s.size()+2);
3484         writeU16(&data[0], TOCLIENT_INVENTORY);
3485         memcpy(&data[2], s.c_str(), s.size());
3486         
3487         // Send as reliable
3488         m_con.Send(peer_id, 0, data, true);
3489 }
3490
3491 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3492 {
3493         DSTACK(__FUNCTION_NAME);
3494         
3495         std::ostringstream os(std::ios_base::binary);
3496         u8 buf[12];
3497         
3498         // Write command
3499         writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3500         os.write((char*)buf, 2);
3501         
3502         // Write length
3503         writeU16(buf, message.size());
3504         os.write((char*)buf, 2);
3505         
3506         // Write string
3507         for(u32 i=0; i<message.size(); i++)
3508         {
3509                 u16 w = message[i];
3510                 writeU16(buf, w);
3511                 os.write((char*)buf, 2);
3512         }
3513         
3514         // Make data buffer
3515         std::string s = os.str();
3516         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3517         // Send as reliable
3518         m_con.Send(peer_id, 0, data, true);
3519 }
3520
3521 void Server::BroadcastChatMessage(const std::wstring &message)
3522 {
3523         for(core::map<u16, RemoteClient*>::Iterator
3524                 i = m_clients.getIterator();
3525                 i.atEnd() == false; i++)
3526         {
3527                 // Get client and check that it is valid
3528                 RemoteClient *client = i.getNode()->getValue();
3529                 assert(client->peer_id == i.getNode()->getKey());
3530                 if(client->serialization_version == SER_FMT_VER_INVALID)
3531                         continue;
3532
3533                 SendChatMessage(client->peer_id, message);
3534         }
3535 }
3536
3537 void Server::SendPlayerHP(Player *player)
3538 {
3539         SendHP(m_con, player->peer_id, player->hp);
3540 }
3541
3542 void Server::SendMovePlayer(Player *player)
3543 {
3544         DSTACK(__FUNCTION_NAME);
3545         std::ostringstream os(std::ios_base::binary);
3546
3547         writeU16(os, TOCLIENT_MOVE_PLAYER);
3548         writeV3F1000(os, player->getPosition());
3549         writeF1000(os, player->getPitch());
3550         writeF1000(os, player->getYaw());
3551         
3552         {
3553                 v3f pos = player->getPosition();
3554                 f32 pitch = player->getPitch();
3555                 f32 yaw = player->getYaw();
3556                 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3557                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3558                                 <<" pitch="<<pitch
3559                                 <<" yaw="<<yaw
3560                                 <<std::endl;
3561         }
3562
3563         // Make data buffer
3564         std::string s = os.str();
3565         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3566         // Send as reliable
3567         m_con.Send(player->peer_id, 0, data, true);
3568 }
3569
3570 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3571         core::list<u16> *far_players, float far_d_nodes)
3572 {
3573         float maxd = far_d_nodes*BS;
3574         v3f p_f = intToFloat(p, BS);
3575
3576         // Create packet
3577         u32 replysize = 8;
3578         SharedBuffer<u8> reply(replysize);
3579         writeU16(&reply[0], TOCLIENT_REMOVENODE);
3580         writeS16(&reply[2], p.X);
3581         writeS16(&reply[4], p.Y);
3582         writeS16(&reply[6], p.Z);
3583
3584         for(core::map<u16, RemoteClient*>::Iterator
3585                 i = m_clients.getIterator();
3586                 i.atEnd() == false; i++)
3587         {
3588                 // Get client and check that it is valid
3589                 RemoteClient *client = i.getNode()->getValue();
3590                 assert(client->peer_id == i.getNode()->getKey());
3591                 if(client->serialization_version == SER_FMT_VER_INVALID)
3592                         continue;
3593
3594                 // Don't send if it's the same one
3595                 if(client->peer_id == ignore_id)
3596                         continue;
3597                 
3598                 if(far_players)
3599                 {
3600                         // Get player
3601                         Player *player = m_env.getPlayer(client->peer_id);
3602                         if(player)
3603                         {
3604                                 // If player is far away, only set modified blocks not sent
3605                                 v3f player_pos = player->getPosition();
3606                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3607                                 {
3608                                         far_players->push_back(client->peer_id);
3609                                         continue;
3610                                 }
3611                         }
3612                 }
3613
3614                 // Send as reliable
3615                 m_con.Send(client->peer_id, 0, reply, true);
3616         }
3617 }
3618
3619 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3620                 core::list<u16> *far_players, float far_d_nodes)
3621 {
3622         float maxd = far_d_nodes*BS;
3623         v3f p_f = intToFloat(p, BS);
3624
3625         for(core::map<u16, RemoteClient*>::Iterator
3626                 i = m_clients.getIterator();
3627                 i.atEnd() == false; i++)
3628         {
3629                 // Get client and check that it is valid
3630                 RemoteClient *client = i.getNode()->getValue();
3631                 assert(client->peer_id == i.getNode()->getKey());
3632                 if(client->serialization_version == SER_FMT_VER_INVALID)
3633                         continue;
3634
3635                 // Don't send if it's the same one
3636                 if(client->peer_id == ignore_id)
3637                         continue;
3638
3639                 if(far_players)
3640                 {
3641                         // Get player
3642                         Player *player = m_env.getPlayer(client->peer_id);
3643                         if(player)
3644                         {
3645                                 // If player is far away, only set modified blocks not sent
3646                                 v3f player_pos = player->getPosition();
3647                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3648                                 {
3649                                         far_players->push_back(client->peer_id);
3650                                         continue;
3651                                 }
3652                         }
3653                 }
3654
3655                 // Create packet
3656                 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3657                 SharedBuffer<u8> reply(replysize);
3658                 writeU16(&reply[0], TOCLIENT_ADDNODE);
3659                 writeS16(&reply[2], p.X);
3660                 writeS16(&reply[4], p.Y);
3661                 writeS16(&reply[6], p.Z);
3662                 n.serialize(&reply[8], client->serialization_version);
3663
3664                 // Send as reliable
3665                 m_con.Send(client->peer_id, 0, reply, true);
3666         }
3667 }
3668
3669 void Server::setBlockNotSent(v3s16 p)
3670 {
3671         for(core::map<u16, RemoteClient*>::Iterator
3672                 i = m_clients.getIterator();
3673                 i.atEnd()==false; i++)
3674         {
3675                 RemoteClient *client = i.getNode()->getValue();
3676                 client->SetBlockNotSent(p);
3677         }
3678 }
3679
3680 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3681 {
3682         DSTACK(__FUNCTION_NAME);
3683
3684         v3s16 p = block->getPos();
3685         
3686 #if 0
3687         // Analyze it a bit
3688         bool completely_air = true;
3689         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3690         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3691         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3692         {
3693                 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3694                 {
3695                         completely_air = false;
3696                         x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3697                 }
3698         }
3699
3700         // Print result
3701         dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3702         if(completely_air)
3703                 dstream<<"[completely air] ";
3704         dstream<<std::endl;
3705 #endif
3706
3707         /*
3708                 Create a packet with the block in the right format
3709         */
3710         
3711         std::ostringstream os(std::ios_base::binary);
3712         block->serialize(os, ver);
3713         std::string s = os.str();
3714         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3715
3716         u32 replysize = 8 + blockdata.getSize();
3717         SharedBuffer<u8> reply(replysize);
3718         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3719         writeS16(&reply[2], p.X);
3720         writeS16(&reply[4], p.Y);
3721         writeS16(&reply[6], p.Z);
3722         memcpy(&reply[8], *blockdata, blockdata.getSize());
3723
3724         /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3725                         <<":  \tpacket size: "<<replysize<<std::endl;*/
3726         
3727         /*
3728                 Send packet
3729         */
3730         m_con.Send(peer_id, 1, reply, true);
3731 }
3732
3733 void Server::SendBlocks(float dtime)
3734 {
3735         DSTACK(__FUNCTION_NAME);
3736
3737         JMutexAutoLock envlock(m_env_mutex);
3738         JMutexAutoLock conlock(m_con_mutex);
3739
3740         //TimeTaker timer("Server::SendBlocks");
3741
3742         core::array<PrioritySortedBlockTransfer> queue;
3743
3744         s32 total_sending = 0;
3745         
3746         {
3747                 ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
3748
3749                 for(core::map<u16, RemoteClient*>::Iterator
3750                         i = m_clients.getIterator();
3751                         i.atEnd() == false; i++)
3752                 {
3753                         RemoteClient *client = i.getNode()->getValue();
3754                         assert(client->peer_id == i.getNode()->getKey());
3755
3756                         total_sending += client->SendingCount();
3757                         
3758                         if(client->serialization_version == SER_FMT_VER_INVALID)
3759                                 continue;
3760                         
3761                         client->GetNextBlocks(this, dtime, queue);
3762                 }
3763         }
3764
3765         // Sort.
3766         // Lowest priority number comes first.
3767         // Lowest is most important.
3768         queue.sort();
3769
3770         for(u32 i=0; i<queue.size(); i++)
3771         {
3772                 //TODO: Calculate limit dynamically
3773                 if(total_sending >= g_settings.getS32
3774                                 ("max_simultaneous_block_sends_server_total"))
3775                         break;
3776                 
3777                 PrioritySortedBlockTransfer q = queue[i];
3778
3779                 MapBlock *block = NULL;
3780                 try
3781                 {
3782                         block = m_env.getMap().getBlockNoCreate(q.pos);
3783                 }
3784                 catch(InvalidPositionException &e)
3785                 {
3786                         continue;
3787                 }
3788
3789                 RemoteClient *client = getClient(q.peer_id);
3790
3791                 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3792
3793                 client->SentBlock(q.pos);
3794
3795                 total_sending++;
3796         }
3797 }
3798
3799 /*
3800         Something random
3801 */
3802
3803 void Server::UpdateCrafting(u16 peer_id)
3804 {
3805         DSTACK(__FUNCTION_NAME);
3806         
3807         Player* player = m_env.getPlayer(peer_id);
3808         assert(player);
3809
3810         /*
3811                 Calculate crafting stuff
3812         */
3813         if(g_settings.getBool("creative_mode") == false)
3814         {
3815                 InventoryList *clist = player->inventory.getList("craft");
3816                 InventoryList *rlist = player->inventory.getList("craftresult");
3817
3818                 if(rlist->getUsedSlots() == 0)
3819                         player->craftresult_is_preview = true;
3820
3821                 if(rlist && player->craftresult_is_preview)
3822                 {
3823                         rlist->clearItems();
3824                 }
3825                 if(clist && rlist && player->craftresult_is_preview)
3826                 {
3827                         InventoryItem *items[9];
3828                         for(u16 i=0; i<9; i++)
3829                         {
3830                                 items[i] = clist->getItem(i);
3831                         }
3832                         
3833                         // Get result of crafting grid
3834                         InventoryItem *result = craft_get_result(items);
3835                         if(result)
3836                                 rlist->addItem(result);
3837                 }
3838         
3839         } // if creative_mode == false
3840 }
3841
3842 RemoteClient* Server::getClient(u16 peer_id)
3843 {
3844         DSTACK(__FUNCTION_NAME);
3845         //JMutexAutoLock lock(m_con_mutex);
3846         core::map<u16, RemoteClient*>::Node *n;
3847         n = m_clients.find(peer_id);
3848         // A client should exist for all peers
3849         assert(n != NULL);
3850         return n->getValue();
3851 }
3852
3853 std::wstring Server::getStatusString()
3854 {
3855         std::wostringstream os(std::ios_base::binary);
3856         os<<L"# Server: ";
3857         // Version
3858         os<<L"version="<<narrow_to_wide(VERSION_STRING);
3859         // Uptime
3860         os<<L", uptime="<<m_uptime.get();
3861         // Information about clients
3862         os<<L", clients={";
3863         for(core::map<u16, RemoteClient*>::Iterator
3864                 i = m_clients.getIterator();
3865                 i.atEnd() == false; i++)
3866         {
3867                 // Get client and check that it is valid
3868                 RemoteClient *client = i.getNode()->getValue();
3869                 assert(client->peer_id == i.getNode()->getKey());
3870                 if(client->serialization_version == SER_FMT_VER_INVALID)
3871                         continue;
3872                 // Get player
3873                 Player *player = m_env.getPlayer(client->peer_id);
3874                 // Get name of player
3875                 std::wstring name = L"unknown";
3876                 if(player != NULL)
3877                         name = narrow_to_wide(player->getName());
3878                 // Add name to information string
3879                 os<<name<<L",";
3880         }
3881         os<<L"}";
3882         if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
3883                 os<<" WARNING: Map saving is disabled."<<std::endl;
3884         return os.str();
3885 }
3886
3887 v3f findSpawnPos(ServerMap &map)
3888 {
3889         //return v3f(50,50,50)*BS;
3890         
3891         v2s16 nodepos;
3892         s16 groundheight = 0;
3893         
3894         // Try to find a good place a few times
3895         for(s32 i=0; i<1000; i++)
3896         {
3897                 s32 range = 1 + i;
3898                 // We're going to try to throw the player to this position
3899                 nodepos = v2s16(-range + (myrand()%(range*2)),
3900                                 -range + (myrand()%(range*2)));
3901                 v2s16 sectorpos = getNodeSectorPos(nodepos);
3902                 // Get sector (NOTE: Don't get because it's slow)
3903                 //m_env.getMap().emergeSector(sectorpos);
3904                 // Get ground height at point (fallbacks to heightmap function)
3905                 groundheight = map.findGroundLevel(nodepos);
3906                 // Don't go underwater
3907                 if(groundheight < WATER_LEVEL)
3908                 {
3909                         //dstream<<"-> Underwater"<<std::endl;
3910                         continue;
3911                 }
3912                 // Don't go to high places
3913                 if(groundheight > WATER_LEVEL + 4)
3914                 {
3915                         //dstream<<"-> Underwater"<<std::endl;
3916                         continue;
3917                 }
3918
3919                 // Found a good place
3920                 //dstream<<"Searched through "<<i<<" places."<<std::endl;
3921                 break;
3922         }
3923         
3924         // If no suitable place was not found, go above water at least.
3925         if(groundheight < WATER_LEVEL)
3926                 groundheight = WATER_LEVEL;
3927
3928         return intToFloat(v3s16(
3929                         nodepos.X,
3930                         groundheight + 2,
3931                         nodepos.Y
3932                         ), BS);
3933 }
3934
3935 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
3936 {
3937         /*
3938                 Try to get an existing player
3939         */
3940         Player *player = m_env.getPlayer(name);
3941         if(player != NULL)
3942         {
3943                 // If player is already connected, cancel
3944                 if(player->peer_id != 0)
3945                 {
3946                         dstream<<"emergePlayer(): Player already connected"<<std::endl;
3947                         return NULL;
3948                 }
3949
3950                 // Got one.
3951                 player->peer_id = peer_id;
3952                 
3953                 // Reset inventory to creative if in creative mode
3954                 if(g_settings.getBool("creative_mode"))
3955                 {
3956                         craft_set_creative_inventory(player);
3957                 }
3958
3959                 return player;
3960         }
3961
3962         /*
3963                 If player with the wanted peer_id already exists, cancel.
3964         */
3965         if(m_env.getPlayer(peer_id) != NULL)
3966         {
3967                 dstream<<"emergePlayer(): Player with wrong name but same"
3968                                 " peer_id already exists"<<std::endl;
3969                 return NULL;
3970         }
3971         
3972         /*
3973                 Create a new player
3974         */
3975         {
3976                 player = new ServerRemotePlayer();
3977                 //player->peer_id = c.peer_id;
3978                 //player->peer_id = PEER_ID_INEXISTENT;
3979                 player->peer_id = peer_id;
3980                 player->updateName(name);
3981                 m_authmanager.add(name);
3982                 m_authmanager.setPassword(name, password);
3983                 m_authmanager.setPrivs(name,
3984                                 stringToPrivs(g_settings.get("default_privs")));
3985
3986                 /*
3987                         Set player position
3988                 */
3989                 
3990                 dstream<<"Server: Finding spawn place for player \""
3991                                 <<player->getName()<<"\""<<std::endl;
3992
3993                 v3f pos = findSpawnPos(m_env.getServerMap());
3994
3995                 player->setPosition(pos);
3996
3997                 /*
3998                         Add player to environment
3999                 */
4000
4001                 m_env.addPlayer(player);
4002
4003                 /*
4004                         Add stuff to inventory
4005                 */
4006                 
4007                 if(g_settings.getBool("creative_mode"))
4008                 {
4009                         craft_set_creative_inventory(player);
4010                 }
4011                 else if(g_settings.getBool("give_initial_stuff"))
4012                 {
4013                         craft_give_initial_stuff(player);
4014                 }
4015
4016                 return player;
4017                 
4018         } // create new player
4019 }
4020
4021 void Server::handlePeerChange(PeerChange &c)
4022 {
4023         JMutexAutoLock envlock(m_env_mutex);
4024         JMutexAutoLock conlock(m_con_mutex);
4025         
4026         if(c.type == PEER_ADDED)
4027         {
4028                 /*
4029                         Add
4030                 */
4031
4032                 // Error check
4033                 core::map<u16, RemoteClient*>::Node *n;
4034                 n = m_clients.find(c.peer_id);
4035                 // The client shouldn't already exist
4036                 assert(n == NULL);
4037
4038                 // Create client
4039                 RemoteClient *client = new RemoteClient();
4040                 client->peer_id = c.peer_id;
4041                 m_clients.insert(client->peer_id, client);
4042
4043         } // PEER_ADDED
4044         else if(c.type == PEER_REMOVED)
4045         {
4046                 /*
4047                         Delete
4048                 */
4049
4050                 // Error check
4051                 core::map<u16, RemoteClient*>::Node *n;
4052                 n = m_clients.find(c.peer_id);
4053                 // The client should exist
4054                 assert(n != NULL);
4055                 
4056                 /*
4057                         Mark objects to be not known by the client
4058                 */
4059                 RemoteClient *client = n->getValue();
4060                 // Handle objects
4061                 for(core::map<u16, bool>::Iterator
4062                                 i = client->m_known_objects.getIterator();
4063                                 i.atEnd()==false; i++)
4064                 {
4065                         // Get object
4066                         u16 id = i.getNode()->getKey();
4067                         ServerActiveObject* obj = m_env.getActiveObject(id);
4068                         
4069                         if(obj && obj->m_known_by_count > 0)
4070                                 obj->m_known_by_count--;
4071                 }
4072
4073                 // Collect information about leaving in chat
4074                 std::wstring message;
4075                 {
4076                         std::wstring name = L"unknown";
4077                         Player *player = m_env.getPlayer(c.peer_id);
4078                         if(player != NULL)
4079                                 name = narrow_to_wide(player->getName());
4080                         
4081                         message += L"*** ";
4082                         message += name;
4083                         message += L" left game";
4084                         if(c.timeout)
4085                                 message += L" (timed out)";
4086                 }
4087
4088                 /*// Delete player
4089                 {
4090                         m_env.removePlayer(c.peer_id);
4091                 }*/
4092
4093                 // Set player client disconnected
4094                 {
4095                         Player *player = m_env.getPlayer(c.peer_id);
4096                         if(player != NULL)
4097                                 player->peer_id = 0;
4098                 }
4099                 
4100                 // Delete client
4101                 delete m_clients[c.peer_id];
4102                 m_clients.remove(c.peer_id);
4103
4104                 // Send player info to all remaining clients
4105                 SendPlayerInfos();
4106                 
4107                 // Send leave chat message to all remaining clients
4108                 BroadcastChatMessage(message);
4109                 
4110         } // PEER_REMOVED
4111         else
4112         {
4113                 assert(0);
4114         }
4115 }
4116
4117 void Server::handlePeerChanges()
4118 {
4119         while(m_peer_change_queue.size() > 0)
4120         {
4121                 PeerChange c = m_peer_change_queue.pop_front();
4122
4123                 dout_server<<"Server: Handling peer change: "
4124                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4125                                 <<std::endl;
4126
4127                 handlePeerChange(c);
4128         }
4129 }
4130
4131 u64 Server::getPlayerPrivs(Player *player)
4132 {
4133         if(player==NULL)
4134                 return 0;
4135         std::string playername = player->getName();
4136         // Local player gets all privileges regardless of
4137         // what's set on their account.
4138         if(g_settings.get("name") == playername)
4139         {
4140                 return PRIV_ALL;
4141         }
4142         else
4143         {
4144                 return getPlayerAuthPrivs(playername);
4145         }
4146 }
4147
4148 void dedicated_server_loop(Server &server, bool &kill)
4149 {
4150         DSTACK(__FUNCTION_NAME);
4151         
4152         dstream<<DTIME<<std::endl;
4153         dstream<<"========================"<<std::endl;
4154         dstream<<"Running dedicated server"<<std::endl;
4155         dstream<<"========================"<<std::endl;
4156         dstream<<std::endl;
4157
4158         IntervalLimiter m_profiler_interval;
4159
4160         for(;;)
4161         {
4162                 // This is kind of a hack but can be done like this
4163                 // because server.step() is very light
4164                 {
4165                         ScopeProfiler sp(&g_profiler, "dedicated server sleep");
4166                         sleep_ms(30);
4167                 }
4168                 server.step(0.030);
4169
4170                 if(server.getShutdownRequested() || kill)
4171                 {
4172                         dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4173                         break;
4174                 }
4175
4176                 /*
4177                         Profiler
4178                 */
4179                 float profiler_print_interval =
4180                                 g_settings.getFloat("profiler_print_interval");
4181                 if(profiler_print_interval != 0)
4182                 {
4183                         if(m_profiler_interval.step(0.030, profiler_print_interval))
4184                         {
4185                                 dstream<<"Profiler:"<<std::endl;
4186                                 g_profiler.print(dstream);
4187                                 g_profiler.clear();
4188                         }
4189                 }
4190                 
4191                 /*
4192                         Player info
4193                 */
4194                 static int counter = 0;
4195                 counter--;
4196                 if(counter <= 0)
4197                 {
4198                         counter = 10;
4199
4200                         core::list<PlayerInfo> list = server.getPlayerInfo();
4201                         core::list<PlayerInfo>::Iterator i;
4202                         static u32 sum_old = 0;
4203                         u32 sum = PIChecksum(list);
4204                         if(sum != sum_old)
4205                         {
4206                                 dstream<<DTIME<<"Player info:"<<std::endl;
4207                                 for(i=list.begin(); i!=list.end(); i++)
4208                                 {
4209                                         i->PrintLine(&dstream);
4210                                 }
4211                         }
4212                         sum_old = sum;
4213                 }
4214         }
4215 }
4216
4217