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