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