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