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