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