Saner block modification flag operation for not saving everything always
[oweals/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                                 item = NULL;
2753
2754                                 if(mineral != MINERAL_NONE)
2755                                   item = getDiggedMineralItem(mineral);
2756                         
2757                                 // If not mineral
2758                                 if(item == NULL)
2759                                 {
2760                                         std::string &extra_dug_s = content_features(material).extra_dug_item;
2761                                         s32 extra_rarity = content_features(material).extra_dug_item_rarity;
2762                                         if(extra_dug_s != "" && extra_rarity != 0
2763                                            && myrand() % extra_rarity == 0)
2764                                         {
2765                                                 std::istringstream is(extra_dug_s, std::ios::binary);
2766                                                 item = InventoryItem::deSerialize(is);
2767                                         }
2768                                 }
2769                         
2770                                 if(item != NULL)
2771                                 {
2772                                         // Add a item to inventory
2773                                         player->inventory.addItem("main", item);
2774
2775                                         // Send inventory
2776                                         UpdateCrafting(player->peer_id);
2777                                         SendInventory(player->peer_id);
2778                                 }
2779                         }
2780
2781                         /*
2782                                 Remove the node
2783                                 (this takes some time so it is done after the quick stuff)
2784                         */
2785                         {
2786                                 MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2787
2788                                 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
2789                         }
2790                         /*
2791                                 Set blocks not sent to far players
2792                         */
2793                         for(core::list<u16>::Iterator
2794                                         i = far_players.begin();
2795                                         i != far_players.end(); i++)
2796                         {
2797                                 u16 peer_id = *i;
2798                                 RemoteClient *client = getClient(peer_id);
2799                                 if(client==NULL)
2800                                         continue;
2801                                 client->SetBlocksNotSent(modified_blocks);
2802                         }
2803                 }
2804                 
2805                 /*
2806                         1: place block
2807                 */
2808                 else if(action == 1)
2809                 {
2810
2811                         InventoryList *ilist = player->inventory.getList("main");
2812                         if(ilist == NULL)
2813                                 return;
2814
2815                         // Get item
2816                         InventoryItem *item = ilist->getItem(item_i);
2817                         
2818                         // If there is no item, it is not possible to add it anywhere
2819                         if(item == NULL)
2820                                 return;
2821                         
2822                         /*
2823                                 Handle material items
2824                         */
2825                         if(std::string("MaterialItem") == item->getName())
2826                         {
2827                                 try{
2828                                         // Don't add a node if this is not a free space
2829                                         MapNode n2 = m_env.getMap().getNode(p_over);
2830                                         bool no_enough_privs =
2831                                                         ((getPlayerPrivs(player) & PRIV_BUILD)==0);
2832                                         if(no_enough_privs)
2833                                                 dstream<<"Player "<<player->getName()<<" cannot add node"
2834                                                         <<" because privileges are "<<getPlayerPrivs(player)
2835                                                         <<std::endl;
2836
2837                                         if(content_features(n2).buildable_to == false
2838                                                 || no_enough_privs)
2839                                         {
2840                                                 // Client probably has wrong data.
2841                                                 // Set block not sent, so that client will get
2842                                                 // a valid one.
2843                                                 dstream<<"Client "<<peer_id<<" tried to place"
2844                                                                 <<" node in invalid position; setting"
2845                                                                 <<" MapBlock not sent."<<std::endl;
2846                                                 RemoteClient *client = getClient(peer_id);
2847                                                 v3s16 blockpos = getNodeBlockPos(p_over);
2848                                                 client->SetBlockNotSent(blockpos);
2849                                                 return;
2850                                         }
2851                                 }
2852                                 catch(InvalidPositionException &e)
2853                                 {
2854                                         derr_server<<"Server: Ignoring ADDNODE: Node not found"
2855                                                         <<" Adding block to emerge queue."
2856                                                         <<std::endl;
2857                                         m_emerge_queue.addBlock(peer_id,
2858                                                         getNodeBlockPos(p_over), BLOCK_EMERGE_FLAG_FROMDISK);
2859                                         return;
2860                                 }
2861
2862                                 // Reset build time counter
2863                                 getClient(peer->id)->m_time_from_building = 0.0;
2864                                 
2865                                 // Create node data
2866                                 MaterialItem *mitem = (MaterialItem*)item;
2867                                 MapNode n;
2868                                 n.setContent(mitem->getMaterial());
2869
2870                                 // Calculate direction for wall mounted stuff
2871                                 if(content_features(n).wall_mounted)
2872                                         n.param2 = packDir(p_under - p_over);
2873
2874                                 // Calculate the direction for furnaces and chests and stuff
2875                                 if(content_features(n).param_type == CPT_FACEDIR_SIMPLE)
2876                                 {
2877                                         v3f playerpos = player->getPosition();
2878                                         v3f blockpos = intToFloat(p_over, BS) - playerpos;
2879                                         blockpos = blockpos.normalize();
2880                                         n.param1 = 0;
2881                                         if (fabs(blockpos.X) > fabs(blockpos.Z)) {
2882                                                 if (blockpos.X < 0)
2883                                                         n.param1 = 3;
2884                                                 else
2885                                                         n.param1 = 1;
2886                                         } else {
2887                                                 if (blockpos.Z < 0)
2888                                                         n.param1 = 2;
2889                                                 else
2890                                                         n.param1 = 0;
2891                                         }
2892                                 }
2893
2894                                 /*
2895                                         Send to all close-by players
2896                                 */
2897                                 core::list<u16> far_players;
2898                                 sendAddNode(p_over, n, 0, &far_players, 30);
2899                                 
2900                                 /*
2901                                         Handle inventory
2902                                 */
2903                                 InventoryList *ilist = player->inventory.getList("main");
2904                                 if(g_settings.getBool("creative_mode") == false && ilist)
2905                                 {
2906                                         // Remove from inventory and send inventory
2907                                         if(mitem->getCount() == 1)
2908                                                 ilist->deleteItem(item_i);
2909                                         else
2910                                                 mitem->remove(1);
2911                                         // Send inventory
2912                                         UpdateCrafting(peer_id);
2913                                         SendInventory(peer_id);
2914                                 }
2915                                 
2916                                 /*
2917                                         Add node.
2918
2919                                         This takes some time so it is done after the quick stuff
2920                                 */
2921                                 core::map<v3s16, MapBlock*> modified_blocks;
2922                                 {
2923                                         MapEditEventIgnorer ign(&m_ignore_map_edit_events);
2924
2925                                         std::string p_name = std::string(player->getName());
2926                                         m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks, p_name);
2927                                 }
2928                                 /*
2929                                         Set blocks not sent to far players
2930                                 */
2931                                 for(core::list<u16>::Iterator
2932                                                 i = far_players.begin();
2933                                                 i != far_players.end(); i++)
2934                                 {
2935                                         u16 peer_id = *i;
2936                                         RemoteClient *client = getClient(peer_id);
2937                                         if(client==NULL)
2938                                                 continue;
2939                                         client->SetBlocksNotSent(modified_blocks);
2940                                 }
2941
2942                                 /*
2943                                         Calculate special events
2944                                 */
2945                                 
2946                                 /*if(n.d == CONTENT_MESE)
2947                                 {
2948                                         u32 count = 0;
2949                                         for(s16 z=-1; z<=1; z++)
2950                                         for(s16 y=-1; y<=1; y++)
2951                                         for(s16 x=-1; x<=1; x++)
2952                                         {
2953                                                 
2954                                         }
2955                                 }*/
2956                         }
2957                         /*
2958                                 Place other item (not a block)
2959                         */
2960                         else
2961                         {
2962                                 v3s16 blockpos = getNodeBlockPos(p_over);
2963                                 
2964                                 /*
2965                                         Check that the block is loaded so that the item
2966                                         can properly be added to the static list too
2967                                 */
2968                                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
2969                                 if(block==NULL)
2970                                 {
2971                                         derr_server<<"Error while placing object: "
2972                                                         "block not found"<<std::endl;
2973                                         return;
2974                                 }
2975
2976                                 /*
2977                                         If in creative mode, item dropping is disabled unless
2978                                         player has build privileges
2979                                 */
2980                                 if(g_settings.getBool("creative_mode") &&
2981                                         (getPlayerPrivs(player) & PRIV_BUILD) == 0)
2982                                 {
2983                                         derr_server<<"Not allowing player to drop item: "
2984                                                         "creative mode and no build privs"<<std::endl;
2985                                         return;
2986                                 }
2987
2988                                 dout_server<<"Placing a miscellaneous item on map"
2989                                                 <<std::endl;
2990                                 
2991                                 // Calculate a position for it
2992                                 v3f pos = intToFloat(p_over, BS);
2993                                 //pos.Y -= BS*0.45;
2994                                 pos.Y -= BS*0.25; // let it drop a bit
2995                                 // Randomize a bit
2996                                 pos.X += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2997                                 pos.Z += BS*0.2*(float)myrand_range(-1000,1000)/1000.0;
2998
2999                                 /*
3000                                         Create the object
3001                                 */
3002                                 ServerActiveObject *obj = item->createSAO(&m_env, 0, pos);
3003
3004                                 if(obj == NULL)
3005                                 {
3006                                         derr_server<<"WARNING: item resulted in NULL object, "
3007                                                         <<"not placing onto map"
3008                                                         <<std::endl;
3009                                 }
3010                                 else
3011                                 {
3012                                         // Add the object to the environment
3013                                         m_env.addActiveObject(obj);
3014                                         
3015                                         dout_server<<"Placed object"<<std::endl;
3016
3017                                         if(g_settings.getBool("creative_mode") == false)
3018                                         {
3019                                                 // Delete the right amount of items from the slot
3020                                                 u16 dropcount = item->getDropCount();
3021                                                 
3022                                                 // Delete item if all gone
3023                                                 if(item->getCount() <= dropcount)
3024                                                 {
3025                                                         if(item->getCount() < dropcount)
3026                                                                 dstream<<"WARNING: Server: dropped more items"
3027                                                                                 <<" than the slot contains"<<std::endl;
3028                                                         
3029                                                         InventoryList *ilist = player->inventory.getList("main");
3030                                                         if(ilist)
3031                                                                 // Remove from inventory and send inventory
3032                                                                 ilist->deleteItem(item_i);
3033                                                 }
3034                                                 // Else decrement it
3035                                                 else
3036                                                         item->remove(dropcount);
3037                                                 
3038                                                 // Send inventory
3039                                                 UpdateCrafting(peer_id);
3040                                                 SendInventory(peer_id);
3041                                         }
3042                                 }
3043                         }
3044
3045                 } // action == 1
3046
3047                 /*
3048                         Catch invalid actions
3049                 */
3050                 else
3051                 {
3052                         derr_server<<"WARNING: Server: Invalid action "
3053                                         <<action<<std::endl;
3054                 }
3055         }
3056 #if 0
3057         else if(command == TOSERVER_RELEASE)
3058         {
3059                 if(datasize < 3)
3060                         return;
3061                 /*
3062                         length: 3
3063                         [0] u16 command
3064                         [2] u8 button
3065                 */
3066                 dstream<<"TOSERVER_RELEASE ignored"<<std::endl;
3067         }
3068 #endif
3069         else if(command == TOSERVER_SIGNTEXT)
3070         {
3071                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3072                         return;
3073                 /*
3074                         u16 command
3075                         v3s16 blockpos
3076                         s16 id
3077                         u16 textlen
3078                         textdata
3079                 */
3080                 std::string datastring((char*)&data[2], datasize-2);
3081                 std::istringstream is(datastring, std::ios_base::binary);
3082                 u8 buf[6];
3083                 // Read stuff
3084                 is.read((char*)buf, 6);
3085                 v3s16 blockpos = readV3S16(buf);
3086                 is.read((char*)buf, 2);
3087                 s16 id = readS16(buf);
3088                 is.read((char*)buf, 2);
3089                 u16 textlen = readU16(buf);
3090                 std::string text;
3091                 for(u16 i=0; i<textlen; i++)
3092                 {
3093                         is.read((char*)buf, 1);
3094                         text += (char)buf[0];
3095                 }
3096
3097                 MapBlock *block = NULL;
3098                 try
3099                 {
3100                         block = m_env.getMap().getBlockNoCreate(blockpos);
3101                 }
3102                 catch(InvalidPositionException &e)
3103                 {
3104                         derr_server<<"Error while setting sign text: "
3105                                         "block not found"<<std::endl;
3106                         return;
3107                 }
3108
3109                 MapBlockObject *obj = block->getObject(id);
3110                 if(obj == NULL)
3111                 {
3112                         derr_server<<"Error while setting sign text: "
3113                                         "object not found"<<std::endl;
3114                         return;
3115                 }
3116                 
3117                 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
3118                 {
3119                         derr_server<<"Error while setting sign text: "
3120                                         "object is not a sign"<<std::endl;
3121                         return;
3122                 }
3123
3124                 ((SignObject*)obj)->setText(text);
3125
3126                 obj->getBlock()->setChangedFlag();
3127         }
3128         else if(command == TOSERVER_SIGNNODETEXT)
3129         {
3130                 if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3131                         return;
3132                 /*
3133                         u16 command
3134                         v3s16 p
3135                         u16 textlen
3136                         textdata
3137                 */
3138                 std::string datastring((char*)&data[2], datasize-2);
3139                 std::istringstream is(datastring, std::ios_base::binary);
3140                 u8 buf[6];
3141                 // Read stuff
3142                 is.read((char*)buf, 6);
3143                 v3s16 p = readV3S16(buf);
3144                 is.read((char*)buf, 2);
3145                 u16 textlen = readU16(buf);
3146                 std::string text;
3147                 for(u16 i=0; i<textlen; i++)
3148                 {
3149                         is.read((char*)buf, 1);
3150                         text += (char)buf[0];
3151                 }
3152
3153                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3154                 if(!meta)
3155                         return;
3156                 if(meta->typeId() != CONTENT_SIGN_WALL)
3157                         return;
3158                 SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
3159                 signmeta->setText(text);
3160                 
3161                 v3s16 blockpos = getNodeBlockPos(p);
3162                 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
3163                 if(block)
3164                 {
3165                         block->setChangedFlag();
3166                 }
3167
3168                 for(core::map<u16, RemoteClient*>::Iterator
3169                         i = m_clients.getIterator();
3170                         i.atEnd()==false; i++)
3171                 {
3172                         RemoteClient *client = i.getNode()->getValue();
3173                         client->SetBlockNotSent(blockpos);
3174                 }
3175         }
3176         else if(command == TOSERVER_INVENTORY_ACTION)
3177         {
3178                 /*// Ignore inventory changes if in creative mode
3179                 if(g_settings.getBool("creative_mode") == true)
3180                 {
3181                         dstream<<"TOSERVER_INVENTORY_ACTION: ignoring in creative mode"
3182                                         <<std::endl;
3183                         return;
3184                 }*/
3185                 // Strip command and create a stream
3186                 std::string datastring((char*)&data[2], datasize-2);
3187                 dstream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
3188                 std::istringstream is(datastring, std::ios_base::binary);
3189                 // Create an action
3190                 InventoryAction *a = InventoryAction::deSerialize(is);
3191                 if(a != NULL)
3192                 {
3193                         // Create context
3194                         InventoryContext c;
3195                         c.current_player = player;
3196
3197                         /*
3198                                 Handle craftresult specially if not in creative mode
3199                         */
3200                         bool disable_action = false;
3201                         if(a->getType() == IACTION_MOVE
3202                                         && g_settings.getBool("creative_mode") == false)
3203                         {
3204                                 IMoveAction *ma = (IMoveAction*)a;
3205                                 if(ma->to_inv == "current_player" &&
3206                                                 ma->from_inv == "current_player")
3207                                 {
3208                                         InventoryList *rlist = player->inventory.getList("craftresult");
3209                                         assert(rlist);
3210                                         InventoryList *clist = player->inventory.getList("craft");
3211                                         assert(clist);
3212                                         InventoryList *mlist = player->inventory.getList("main");
3213                                         assert(mlist);
3214                                         /*
3215                                                 Craftresult is no longer preview if something
3216                                                 is moved into it
3217                                         */
3218                                         if(ma->to_list == "craftresult"
3219                                                         && ma->from_list != "craftresult")
3220                                         {
3221                                                 // If it currently is a preview, remove
3222                                                 // its contents
3223                                                 if(player->craftresult_is_preview)
3224                                                 {
3225                                                         rlist->deleteItem(0);
3226                                                 }
3227                                                 player->craftresult_is_preview = false;
3228                                         }
3229                                         /*
3230                                                 Crafting takes place if this condition is true.
3231                                         */
3232                                         if(player->craftresult_is_preview &&
3233                                                         ma->from_list == "craftresult")
3234                                         {
3235                                                 player->craftresult_is_preview = false;
3236                                                 clist->decrementMaterials(1);
3237                                         }
3238                                         /*
3239                                                 If the craftresult is placed on itself, move it to
3240                                                 main inventory instead of doing the action
3241                                         */
3242                                         if(ma->to_list == "craftresult"
3243                                                         && ma->from_list == "craftresult")
3244                                         {
3245                                                 disable_action = true;
3246                                                 
3247                                                 InventoryItem *item1 = rlist->changeItem(0, NULL);
3248                                                 mlist->addItem(item1);
3249                                         }
3250                                 }
3251                                 // Disallow moving items if not allowed to build
3252                                 else if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
3253                                 {
3254                                         return;
3255                                 }
3256                                 // if it's a locking chest, only allow the owner or server admins to move items
3257                                 else if (ma->from_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3258                                 {
3259                                         Strfnd fn(ma->from_inv);
3260                                         std::string id0 = fn.next(":");
3261                                         if(id0 == "nodemeta")
3262                                         {
3263                                                 v3s16 p;
3264                                                 p.X = stoi(fn.next(","));
3265                                                 p.Y = stoi(fn.next(","));
3266                                                 p.Z = stoi(fn.next(","));
3267                                                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3268                                                 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3269                                                         LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3270                                                         if (lcm->getOwner() != player->getName())
3271                                                                 return;
3272                                                 }
3273                                         }
3274                                 }
3275                                 else if (ma->to_inv != "current_player" && (getPlayerPrivs(player) & PRIV_SERVER) == 0)
3276                                 {
3277                                         Strfnd fn(ma->to_inv);
3278                                         std::string id0 = fn.next(":");
3279                                         if(id0 == "nodemeta")
3280                                         {
3281                                                 v3s16 p;
3282                                                 p.X = stoi(fn.next(","));
3283                                                 p.Y = stoi(fn.next(","));
3284                                                 p.Z = stoi(fn.next(","));
3285                                                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3286                                                 if(meta && meta->typeId() == CONTENT_LOCKABLE_CHEST) {
3287                                                         LockingChestNodeMetadata *lcm = (LockingChestNodeMetadata*)meta;
3288                                                         if (lcm->getOwner() != player->getName())
3289                                                                 return;
3290                                                 }
3291                                         }
3292                                 }
3293                         }
3294                         
3295                         if(disable_action == false)
3296                         {
3297                                 // Feed action to player inventory
3298                                 a->apply(&c, this);
3299                                 // Eat the action
3300                                 delete a;
3301                         }
3302                         else
3303                         {
3304                                 // Send inventory
3305                                 UpdateCrafting(player->peer_id);
3306                                 SendInventory(player->peer_id);
3307                         }
3308                 }
3309                 else
3310                 {
3311                         dstream<<"TOSERVER_INVENTORY_ACTION: "
3312                                         <<"InventoryAction::deSerialize() returned NULL"
3313                                         <<std::endl;
3314                 }
3315         }
3316         else if(command == TOSERVER_CHAT_MESSAGE)
3317         {
3318                 /*
3319                         u16 command
3320                         u16 length
3321                         wstring message
3322                 */
3323                 u8 buf[6];
3324                 std::string datastring((char*)&data[2], datasize-2);
3325                 std::istringstream is(datastring, std::ios_base::binary);
3326                 
3327                 // Read stuff
3328                 is.read((char*)buf, 2);
3329                 u16 len = readU16(buf);
3330                 
3331                 std::wstring message;
3332                 for(u16 i=0; i<len; i++)
3333                 {
3334                         is.read((char*)buf, 2);
3335                         message += (wchar_t)readU16(buf);
3336                 }
3337
3338                 // Get player name of this client
3339                 std::wstring name = narrow_to_wide(player->getName());
3340                 
3341                 // Line to send to players
3342                 std::wstring line;
3343                 // Whether to send to the player that sent the line
3344                 bool send_to_sender = false;
3345                 // Whether to send to other players
3346                 bool send_to_others = false;
3347                 
3348                 // Local player gets all privileges regardless of
3349                 // what's set on their account.
3350                 u64 privs = getPlayerPrivs(player);
3351
3352                 // Parse commands
3353                 if(message[0] == L'/')
3354                 {
3355                         size_t strip_size = 1;
3356                         if (message[1] == L'#') // support old-style commans
3357                                 ++strip_size;
3358                         message = message.substr(strip_size);
3359
3360                         WStrfnd f1(message);
3361                         f1.next(L" "); // Skip over /#whatever
3362                         std::wstring paramstring = f1.next(L"");
3363
3364                         ServerCommandContext *ctx = new ServerCommandContext(
3365                                 str_split(message, L' '),
3366                                 paramstring,
3367                                 this,
3368                                 &m_env,
3369                                 player,
3370                                 privs);
3371
3372                         std::wstring reply(processServerCommand(ctx));
3373                         send_to_sender = ctx->flags & SEND_TO_SENDER;
3374                         send_to_others = ctx->flags & SEND_TO_OTHERS;
3375
3376                         if (ctx->flags & SEND_NO_PREFIX)
3377                                 line += reply;
3378                         else
3379                                 line += L"Server: " + reply;
3380
3381                         delete ctx;
3382
3383                 }
3384                 else
3385                 {
3386                         if(privs & PRIV_SHOUT)
3387                         {
3388                                 line += L"<";
3389                                 line += name;
3390                                 line += L"> ";
3391                                 line += message;
3392                                 send_to_others = true;
3393                         }
3394                         else
3395                         {
3396                                 line += L"Server: You are not allowed to shout";
3397                                 send_to_sender = true;
3398                         }
3399                 }
3400                 
3401                 if(line != L"")
3402                 {
3403                         dstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
3404
3405                         /*
3406                                 Send the message to clients
3407                         */
3408                         for(core::map<u16, RemoteClient*>::Iterator
3409                                 i = m_clients.getIterator();
3410                                 i.atEnd() == false; i++)
3411                         {
3412                                 // Get client and check that it is valid
3413                                 RemoteClient *client = i.getNode()->getValue();
3414                                 assert(client->peer_id == i.getNode()->getKey());
3415                                 if(client->serialization_version == SER_FMT_VER_INVALID)
3416                                         continue;
3417
3418                                 // Filter recipient
3419                                 bool sender_selected = (peer_id == client->peer_id);
3420                                 if(sender_selected == true && send_to_sender == false)
3421                                         continue;
3422                                 if(sender_selected == false && send_to_others == false)
3423                                         continue;
3424
3425                                 SendChatMessage(client->peer_id, line);
3426                         }
3427                 }
3428         }
3429         else if(command == TOSERVER_DAMAGE)
3430         {
3431                 if(g_settings.getBool("enable_damage"))
3432                 {
3433                         std::string datastring((char*)&data[2], datasize-2);
3434                         std::istringstream is(datastring, std::ios_base::binary);
3435                         u8 damage = readU8(is);
3436                         if(player->hp > damage)
3437                         {
3438                                 player->hp -= damage;
3439                         }
3440                         else
3441                         {
3442                                 player->hp = 0;
3443
3444                                 dstream<<"TODO: Server: TOSERVER_HP_DECREMENT: Player dies"
3445                                                 <<std::endl;
3446                                 
3447                                 v3f pos = findSpawnPos(m_env.getServerMap());
3448                                 player->setPosition(pos);
3449                                 player->hp = 20;
3450                                 SendMovePlayer(player);
3451                                 SendPlayerHP(player);
3452                                 
3453                                 //TODO: Throw items around
3454                         }
3455                 }
3456
3457                 SendPlayerHP(player);
3458         }
3459         else if(command == TOSERVER_PASSWORD)
3460         {
3461                 /*
3462                         [0] u16 TOSERVER_PASSWORD
3463                         [2] u8[28] old password
3464                         [30] u8[28] new password
3465                 */
3466
3467                 if(datasize != 2+PASSWORD_SIZE*2)
3468                         return;
3469                 /*char password[PASSWORD_SIZE];
3470                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3471                         password[i] = data[2+i];
3472                 password[PASSWORD_SIZE-1] = 0;*/
3473                 std::string oldpwd;
3474                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3475                 {
3476                         char c = data[2+i];
3477                         if(c == 0)
3478                                 break;
3479                         oldpwd += c;
3480                 }
3481                 std::string newpwd;
3482                 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
3483                 {
3484                         char c = data[2+PASSWORD_SIZE+i];
3485                         if(c == 0)
3486                                 break;
3487                         newpwd += c;
3488                 }
3489
3490                 dstream<<"Server: Client requests a password change from "
3491                                 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
3492
3493                 std::string playername = player->getName();
3494
3495                 if(m_authmanager.exists(playername) == false)
3496                 {
3497                         dstream<<"Server: playername not found in authmanager"<<std::endl;
3498                         // Wrong old password supplied!!
3499                         SendChatMessage(peer_id, L"playername not found in authmanager");
3500                         return;
3501                 }
3502
3503                 std::string checkpwd = m_authmanager.getPassword(playername);
3504
3505                 if(oldpwd != checkpwd)
3506                 {
3507                         dstream<<"Server: invalid old password"<<std::endl;
3508                         // Wrong old password supplied!!
3509                         SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
3510                         return;
3511                 }
3512
3513                 m_authmanager.setPassword(playername, newpwd);
3514                 
3515                 dstream<<"Server: password change successful for "<<playername
3516                                 <<std::endl;
3517                 SendChatMessage(peer_id, L"Password change successful");
3518         }
3519         else if (command == TOSERVER_PLAYERITEM)
3520         {
3521                 if (datasize < 2+2)
3522                         return;
3523
3524                 u16 item = readU16(&data[2]);
3525                 player->wieldItem(item);
3526                 SendWieldedItem(player);
3527         }
3528         else
3529         {
3530                 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
3531                                 "unknown command "<<command<<std::endl;
3532         }
3533         
3534         } //try
3535         catch(SendFailedException &e)
3536         {
3537                 derr_server<<"Server::ProcessData(): SendFailedException: "
3538                                 <<"what="<<e.what()
3539                                 <<std::endl;
3540         }
3541 }
3542
3543 void Server::onMapEditEvent(MapEditEvent *event)
3544 {
3545         //dstream<<"Server::onMapEditEvent()"<<std::endl;
3546         if(m_ignore_map_edit_events)
3547                 return;
3548         MapEditEvent *e = event->clone();
3549         m_unsent_map_edit_queue.push_back(e);
3550 }
3551
3552 Inventory* Server::getInventory(InventoryContext *c, std::string id)
3553 {
3554         if(id == "current_player")
3555         {
3556                 assert(c->current_player);
3557                 return &(c->current_player->inventory);
3558         }
3559         
3560         Strfnd fn(id);
3561         std::string id0 = fn.next(":");
3562
3563         if(id0 == "nodemeta")
3564         {
3565                 v3s16 p;
3566                 p.X = stoi(fn.next(","));
3567                 p.Y = stoi(fn.next(","));
3568                 p.Z = stoi(fn.next(","));
3569                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3570                 if(meta)
3571                         return meta->getInventory();
3572                 dstream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
3573                                 <<"no metadata found"<<std::endl;
3574                 return NULL;
3575         }
3576
3577         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3578         return NULL;
3579 }
3580 void Server::inventoryModified(InventoryContext *c, std::string id)
3581 {
3582         if(id == "current_player")
3583         {
3584                 assert(c->current_player);
3585                 // Send inventory
3586                 UpdateCrafting(c->current_player->peer_id);
3587                 SendInventory(c->current_player->peer_id);
3588                 return;
3589         }
3590         
3591         Strfnd fn(id);
3592         std::string id0 = fn.next(":");
3593
3594         if(id0 == "nodemeta")
3595         {
3596                 v3s16 p;
3597                 p.X = stoi(fn.next(","));
3598                 p.Y = stoi(fn.next(","));
3599                 p.Z = stoi(fn.next(","));
3600                 v3s16 blockpos = getNodeBlockPos(p);
3601
3602                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
3603                 if(meta)
3604                         meta->inventoryModified();
3605
3606                 for(core::map<u16, RemoteClient*>::Iterator
3607                         i = m_clients.getIterator();
3608                         i.atEnd()==false; i++)
3609                 {
3610                         RemoteClient *client = i.getNode()->getValue();
3611                         client->SetBlockNotSent(blockpos);
3612                 }
3613
3614                 return;
3615         }
3616
3617         dstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
3618 }
3619
3620 core::list<PlayerInfo> Server::getPlayerInfo()
3621 {
3622         DSTACK(__FUNCTION_NAME);
3623         JMutexAutoLock envlock(m_env_mutex);
3624         JMutexAutoLock conlock(m_con_mutex);
3625         
3626         core::list<PlayerInfo> list;
3627
3628         core::list<Player*> players = m_env.getPlayers();
3629         
3630         core::list<Player*>::Iterator i;
3631         for(i = players.begin();
3632                         i != players.end(); i++)
3633         {
3634                 PlayerInfo info;
3635
3636                 Player *player = *i;
3637
3638                 try{
3639                         con::Peer *peer = m_con.GetPeer(player->peer_id);
3640                         // Copy info from peer to info struct
3641                         info.id = peer->id;
3642                         info.address = peer->address;
3643                         info.avg_rtt = peer->avg_rtt;
3644                 }
3645                 catch(con::PeerNotFoundException &e)
3646                 {
3647                         // Set dummy peer info
3648                         info.id = 0;
3649                         info.address = Address(0,0,0,0,0);
3650                         info.avg_rtt = 0.0;
3651                 }
3652
3653                 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3654                 info.position = player->getPosition();
3655
3656                 list.push_back(info);
3657         }
3658
3659         return list;
3660 }
3661
3662
3663 void Server::peerAdded(con::Peer *peer)
3664 {
3665         DSTACK(__FUNCTION_NAME);
3666         dout_server<<"Server::peerAdded(): peer->id="
3667                         <<peer->id<<std::endl;
3668         
3669         PeerChange c;
3670         c.type = PEER_ADDED;
3671         c.peer_id = peer->id;
3672         c.timeout = false;
3673         m_peer_change_queue.push_back(c);
3674 }
3675
3676 void Server::deletingPeer(con::Peer *peer, bool timeout)
3677 {
3678         DSTACK(__FUNCTION_NAME);
3679         dout_server<<"Server::deletingPeer(): peer->id="
3680                         <<peer->id<<", timeout="<<timeout<<std::endl;
3681         
3682         PeerChange c;
3683         c.type = PEER_REMOVED;
3684         c.peer_id = peer->id;
3685         c.timeout = timeout;
3686         m_peer_change_queue.push_back(c);
3687 }
3688
3689 /*
3690         Static send methods
3691 */
3692
3693 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3694 {
3695         DSTACK(__FUNCTION_NAME);
3696         std::ostringstream os(std::ios_base::binary);
3697
3698         writeU16(os, TOCLIENT_HP);
3699         writeU8(os, hp);
3700
3701         // Make data buffer
3702         std::string s = os.str();
3703         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3704         // Send as reliable
3705         con.Send(peer_id, 0, data, true);
3706 }
3707
3708 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3709                 const std::wstring &reason)
3710 {
3711         DSTACK(__FUNCTION_NAME);
3712         std::ostringstream os(std::ios_base::binary);
3713
3714         writeU16(os, TOCLIENT_ACCESS_DENIED);
3715         os<<serializeWideString(reason);
3716
3717         // Make data buffer
3718         std::string s = os.str();
3719         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3720         // Send as reliable
3721         con.Send(peer_id, 0, data, true);
3722 }
3723
3724 /*
3725         Non-static send methods
3726 */
3727
3728 void Server::SendObjectData(float dtime)
3729 {
3730         DSTACK(__FUNCTION_NAME);
3731
3732         core::map<v3s16, bool> stepped_blocks;
3733         
3734         for(core::map<u16, RemoteClient*>::Iterator
3735                 i = m_clients.getIterator();
3736                 i.atEnd() == false; i++)
3737         {
3738                 u16 peer_id = i.getNode()->getKey();
3739                 RemoteClient *client = i.getNode()->getValue();
3740                 assert(client->peer_id == peer_id);
3741                 
3742                 if(client->serialization_version == SER_FMT_VER_INVALID)
3743                         continue;
3744                 
3745                 client->SendObjectData(this, dtime, stepped_blocks);
3746         }
3747 }
3748
3749 void Server::SendPlayerInfos()
3750 {
3751         DSTACK(__FUNCTION_NAME);
3752
3753         //JMutexAutoLock envlock(m_env_mutex);
3754         
3755         // Get connected players
3756         core::list<Player*> players = m_env.getPlayers(true);
3757         
3758         u32 player_count = players.getSize();
3759         u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
3760
3761         SharedBuffer<u8> data(datasize);
3762         writeU16(&data[0], TOCLIENT_PLAYERINFO);
3763         
3764         u32 start = 2;
3765         core::list<Player*>::Iterator i;
3766         for(i = players.begin();
3767                         i != players.end(); i++)
3768         {
3769                 Player *player = *i;
3770
3771                 /*dstream<<"Server sending player info for player with "
3772                                 "peer_id="<<player->peer_id<<std::endl;*/
3773                 
3774                 writeU16(&data[start], player->peer_id);
3775                 memset((char*)&data[start+2], 0, PLAYERNAME_SIZE);
3776                 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
3777                 start += 2+PLAYERNAME_SIZE;
3778         }
3779
3780         //JMutexAutoLock conlock(m_con_mutex);
3781
3782         // Send as reliable
3783         m_con.SendToAll(0, data, true);
3784 }
3785
3786 void Server::SendInventory(u16 peer_id)
3787 {
3788         DSTACK(__FUNCTION_NAME);
3789         
3790         Player* player = m_env.getPlayer(peer_id);
3791         assert(player);
3792
3793         /*
3794                 Serialize it
3795         */
3796
3797         std::ostringstream os;
3798         //os.imbue(std::locale("C"));
3799
3800         player->inventory.serialize(os);
3801
3802         std::string s = os.str();
3803         
3804         SharedBuffer<u8> data(s.size()+2);
3805         writeU16(&data[0], TOCLIENT_INVENTORY);
3806         memcpy(&data[2], s.c_str(), s.size());
3807         
3808         // Send as reliable
3809         m_con.Send(peer_id, 0, data, true);
3810 }
3811
3812 std::string getWieldedItemString(const Player *player)
3813 {
3814         const InventoryItem *item = player->getWieldItem();
3815         if (item == NULL)
3816                 return std::string("");
3817         std::ostringstream os(std::ios_base::binary);
3818         item->serialize(os);
3819         return os.str();
3820 }
3821
3822 void Server::SendWieldedItem(const Player* player)
3823 {
3824         DSTACK(__FUNCTION_NAME);
3825
3826         assert(player);
3827
3828         std::ostringstream os(std::ios_base::binary);
3829
3830         writeU16(os, TOCLIENT_PLAYERITEM);
3831         writeU16(os, 1);
3832         writeU16(os, player->peer_id);
3833         os<<serializeString(getWieldedItemString(player));
3834
3835         // Make data buffer
3836         std::string s = os.str();
3837         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3838
3839         m_con.SendToAll(0, data, true);
3840 }
3841
3842 void Server::SendPlayerItems()
3843 {
3844         DSTACK(__FUNCTION_NAME);
3845
3846         std::ostringstream os(std::ios_base::binary);
3847         core::list<Player *> players = m_env.getPlayers(true);
3848
3849         writeU16(os, TOCLIENT_PLAYERITEM);
3850         writeU16(os, players.size());
3851         core::list<Player *>::Iterator i;
3852         for(i = players.begin(); i != players.end(); ++i)
3853         {
3854                 Player *p = *i;
3855                 writeU16(os, p->peer_id);
3856                 os<<serializeString(getWieldedItemString(p));
3857         }
3858
3859         // Make data buffer
3860         std::string s = os.str();
3861         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3862
3863         m_con.SendToAll(0, data, true);
3864 }
3865
3866 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3867 {
3868         DSTACK(__FUNCTION_NAME);
3869         
3870         std::ostringstream os(std::ios_base::binary);
3871         u8 buf[12];
3872         
3873         // Write command
3874         writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3875         os.write((char*)buf, 2);
3876         
3877         // Write length
3878         writeU16(buf, message.size());
3879         os.write((char*)buf, 2);
3880         
3881         // Write string
3882         for(u32 i=0; i<message.size(); i++)
3883         {
3884                 u16 w = message[i];
3885                 writeU16(buf, w);
3886                 os.write((char*)buf, 2);
3887         }
3888         
3889         // Make data buffer
3890         std::string s = os.str();
3891         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3892         // Send as reliable
3893         m_con.Send(peer_id, 0, data, true);
3894 }
3895
3896 void Server::BroadcastChatMessage(const std::wstring &message)
3897 {
3898         for(core::map<u16, RemoteClient*>::Iterator
3899                 i = m_clients.getIterator();
3900                 i.atEnd() == false; i++)
3901         {
3902                 // Get client and check that it is valid
3903                 RemoteClient *client = i.getNode()->getValue();
3904                 assert(client->peer_id == i.getNode()->getKey());
3905                 if(client->serialization_version == SER_FMT_VER_INVALID)
3906                         continue;
3907
3908                 SendChatMessage(client->peer_id, message);
3909         }
3910 }
3911
3912 void Server::SendPlayerHP(Player *player)
3913 {
3914         SendHP(m_con, player->peer_id, player->hp);
3915 }
3916
3917 void Server::SendMovePlayer(Player *player)
3918 {
3919         DSTACK(__FUNCTION_NAME);
3920         std::ostringstream os(std::ios_base::binary);
3921
3922         writeU16(os, TOCLIENT_MOVE_PLAYER);
3923         writeV3F1000(os, player->getPosition());
3924         writeF1000(os, player->getPitch());
3925         writeF1000(os, player->getYaw());
3926         
3927         {
3928                 v3f pos = player->getPosition();
3929                 f32 pitch = player->getPitch();
3930                 f32 yaw = player->getYaw();
3931                 dstream<<"Server sending TOCLIENT_MOVE_PLAYER"
3932                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3933                                 <<" pitch="<<pitch
3934                                 <<" yaw="<<yaw
3935                                 <<std::endl;
3936         }
3937
3938         // Make data buffer
3939         std::string s = os.str();
3940         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3941         // Send as reliable
3942         m_con.Send(player->peer_id, 0, data, true);
3943 }
3944
3945 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3946         core::list<u16> *far_players, float far_d_nodes)
3947 {
3948         float maxd = far_d_nodes*BS;
3949         v3f p_f = intToFloat(p, BS);
3950
3951         // Create packet
3952         u32 replysize = 8;
3953         SharedBuffer<u8> reply(replysize);
3954         writeU16(&reply[0], TOCLIENT_REMOVENODE);
3955         writeS16(&reply[2], p.X);
3956         writeS16(&reply[4], p.Y);
3957         writeS16(&reply[6], p.Z);
3958
3959         for(core::map<u16, RemoteClient*>::Iterator
3960                 i = m_clients.getIterator();
3961                 i.atEnd() == false; i++)
3962         {
3963                 // Get client and check that it is valid
3964                 RemoteClient *client = i.getNode()->getValue();
3965                 assert(client->peer_id == i.getNode()->getKey());
3966                 if(client->serialization_version == SER_FMT_VER_INVALID)
3967                         continue;
3968
3969                 // Don't send if it's the same one
3970                 if(client->peer_id == ignore_id)
3971                         continue;
3972                 
3973                 if(far_players)
3974                 {
3975                         // Get player
3976                         Player *player = m_env.getPlayer(client->peer_id);
3977                         if(player)
3978                         {
3979                                 // If player is far away, only set modified blocks not sent
3980                                 v3f player_pos = player->getPosition();
3981                                 if(player_pos.getDistanceFrom(p_f) > maxd)
3982                                 {
3983                                         far_players->push_back(client->peer_id);
3984                                         continue;
3985                                 }
3986                         }
3987                 }
3988
3989                 // Send as reliable
3990                 m_con.Send(client->peer_id, 0, reply, true);
3991         }
3992 }
3993
3994 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3995                 core::list<u16> *far_players, float far_d_nodes)
3996 {
3997         float maxd = far_d_nodes*BS;
3998         v3f p_f = intToFloat(p, BS);
3999
4000         for(core::map<u16, RemoteClient*>::Iterator
4001                 i = m_clients.getIterator();
4002                 i.atEnd() == false; i++)
4003         {
4004                 // Get client and check that it is valid
4005                 RemoteClient *client = i.getNode()->getValue();
4006                 assert(client->peer_id == i.getNode()->getKey());
4007                 if(client->serialization_version == SER_FMT_VER_INVALID)
4008                         continue;
4009
4010                 // Don't send if it's the same one
4011                 if(client->peer_id == ignore_id)
4012                         continue;
4013
4014                 if(far_players)
4015                 {
4016                         // Get player
4017                         Player *player = m_env.getPlayer(client->peer_id);
4018                         if(player)
4019                         {
4020                                 // If player is far away, only set modified blocks not sent
4021                                 v3f player_pos = player->getPosition();
4022                                 if(player_pos.getDistanceFrom(p_f) > maxd)
4023                                 {
4024                                         far_players->push_back(client->peer_id);
4025                                         continue;
4026                                 }
4027                         }
4028                 }
4029
4030                 // Create packet
4031                 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4032                 SharedBuffer<u8> reply(replysize);
4033                 writeU16(&reply[0], TOCLIENT_ADDNODE);
4034                 writeS16(&reply[2], p.X);
4035                 writeS16(&reply[4], p.Y);
4036                 writeS16(&reply[6], p.Z);
4037                 n.serialize(&reply[8], client->serialization_version);
4038
4039                 // Send as reliable
4040                 m_con.Send(client->peer_id, 0, reply, true);
4041         }
4042 }
4043
4044 void Server::setBlockNotSent(v3s16 p)
4045 {
4046         for(core::map<u16, RemoteClient*>::Iterator
4047                 i = m_clients.getIterator();
4048                 i.atEnd()==false; i++)
4049         {
4050                 RemoteClient *client = i.getNode()->getValue();
4051                 client->SetBlockNotSent(p);
4052         }
4053 }
4054
4055 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4056 {
4057         DSTACK(__FUNCTION_NAME);
4058
4059         v3s16 p = block->getPos();
4060         
4061 #if 0
4062         // Analyze it a bit
4063         bool completely_air = true;
4064         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4065         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4066         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4067         {
4068                 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4069                 {
4070                         completely_air = false;
4071                         x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4072                 }
4073         }
4074
4075         // Print result
4076         dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4077         if(completely_air)
4078                 dstream<<"[completely air] ";
4079         dstream<<std::endl;
4080 #endif
4081
4082         /*
4083                 Create a packet with the block in the right format
4084         */
4085         
4086         std::ostringstream os(std::ios_base::binary);
4087         block->serialize(os, ver);
4088         std::string s = os.str();
4089         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4090
4091         u32 replysize = 8 + blockdata.getSize();
4092         SharedBuffer<u8> reply(replysize);
4093         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4094         writeS16(&reply[2], p.X);
4095         writeS16(&reply[4], p.Y);
4096         writeS16(&reply[6], p.Z);
4097         memcpy(&reply[8], *blockdata, blockdata.getSize());
4098
4099         /*dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4100                         <<":  \tpacket size: "<<replysize<<std::endl;*/
4101         
4102         /*
4103                 Send packet
4104         */
4105         m_con.Send(peer_id, 1, reply, true);
4106 }
4107
4108 void Server::SendBlocks(float dtime)
4109 {
4110         DSTACK(__FUNCTION_NAME);
4111
4112         JMutexAutoLock envlock(m_env_mutex);
4113         JMutexAutoLock conlock(m_con_mutex);
4114
4115         //TimeTaker timer("Server::SendBlocks");
4116
4117         core::array<PrioritySortedBlockTransfer> queue;
4118
4119         s32 total_sending = 0;
4120         
4121         {
4122                 ScopeProfiler sp(&g_profiler, "Server: selecting blocks for sending");
4123
4124                 for(core::map<u16, RemoteClient*>::Iterator
4125                         i = m_clients.getIterator();
4126                         i.atEnd() == false; i++)
4127                 {
4128                         RemoteClient *client = i.getNode()->getValue();
4129                         assert(client->peer_id == i.getNode()->getKey());
4130
4131                         total_sending += client->SendingCount();
4132                         
4133                         if(client->serialization_version == SER_FMT_VER_INVALID)
4134                                 continue;
4135                         
4136                         client->GetNextBlocks(this, dtime, queue);
4137                 }
4138         }
4139
4140         // Sort.
4141         // Lowest priority number comes first.
4142         // Lowest is most important.
4143         queue.sort();
4144
4145         for(u32 i=0; i<queue.size(); i++)
4146         {
4147                 //TODO: Calculate limit dynamically
4148                 if(total_sending >= g_settings.getS32
4149                                 ("max_simultaneous_block_sends_server_total"))
4150                         break;
4151                 
4152                 PrioritySortedBlockTransfer q = queue[i];
4153
4154                 MapBlock *block = NULL;
4155                 try
4156                 {
4157                         block = m_env.getMap().getBlockNoCreate(q.pos);
4158                 }
4159                 catch(InvalidPositionException &e)
4160                 {
4161                         continue;
4162                 }
4163
4164                 RemoteClient *client = getClient(q.peer_id);
4165
4166                 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4167
4168                 client->SentBlock(q.pos);
4169
4170                 total_sending++;
4171         }
4172 }
4173
4174 /*
4175         Something random
4176 */
4177
4178 void Server::UpdateCrafting(u16 peer_id)
4179 {
4180         DSTACK(__FUNCTION_NAME);
4181         
4182         Player* player = m_env.getPlayer(peer_id);
4183         assert(player);
4184
4185         /*
4186                 Calculate crafting stuff
4187         */
4188         if(g_settings.getBool("creative_mode") == false)
4189         {
4190                 InventoryList *clist = player->inventory.getList("craft");
4191                 InventoryList *rlist = player->inventory.getList("craftresult");
4192
4193                 if(rlist && rlist->getUsedSlots() == 0)
4194                         player->craftresult_is_preview = true;
4195
4196                 if(rlist && player->craftresult_is_preview)
4197                 {
4198                         rlist->clearItems();
4199                 }
4200                 if(clist && rlist && player->craftresult_is_preview)
4201                 {
4202                         InventoryItem *items[9];
4203                         for(u16 i=0; i<9; i++)
4204                         {
4205                                 items[i] = clist->getItem(i);
4206                         }
4207                         
4208                         // Get result of crafting grid
4209                         InventoryItem *result = craft_get_result(items);
4210                         if(result)
4211                                 rlist->addItem(result);
4212                 }
4213         
4214         } // if creative_mode == false
4215 }
4216
4217 RemoteClient* Server::getClient(u16 peer_id)
4218 {
4219         DSTACK(__FUNCTION_NAME);
4220         //JMutexAutoLock lock(m_con_mutex);
4221         core::map<u16, RemoteClient*>::Node *n;
4222         n = m_clients.find(peer_id);
4223         // A client should exist for all peers
4224         assert(n != NULL);
4225         return n->getValue();
4226 }
4227
4228 std::wstring Server::getStatusString()
4229 {
4230         std::wostringstream os(std::ios_base::binary);
4231         os<<L"# Server: ";
4232         // Version
4233         os<<L"version="<<narrow_to_wide(VERSION_STRING);
4234         // Uptime
4235         os<<L", uptime="<<m_uptime.get();
4236         // Information about clients
4237         os<<L", clients={";
4238         for(core::map<u16, RemoteClient*>::Iterator
4239                 i = m_clients.getIterator();
4240                 i.atEnd() == false; i++)
4241         {
4242                 // Get client and check that it is valid
4243                 RemoteClient *client = i.getNode()->getValue();
4244                 assert(client->peer_id == i.getNode()->getKey());
4245                 if(client->serialization_version == SER_FMT_VER_INVALID)
4246                         continue;
4247                 // Get player
4248                 Player *player = m_env.getPlayer(client->peer_id);
4249                 // Get name of player
4250                 std::wstring name = L"unknown";
4251                 if(player != NULL)
4252                         name = narrow_to_wide(player->getName());
4253                 // Add name to information string
4254                 os<<name<<L",";
4255         }
4256         os<<L"}";
4257         if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == false)
4258                 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4259         if(g_settings.get("motd") != "")
4260                 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings.get("motd"));
4261         return os.str();
4262 }
4263
4264 v3f findSpawnPos(ServerMap &map)
4265 {
4266         //return v3f(50,50,50)*BS;
4267
4268         v2s16 nodepos;
4269         s16 groundheight = 0;
4270         
4271 #if 0
4272         nodepos = v2s16(0,0);
4273         groundheight = 20;
4274 #endif
4275
4276 #if 1
4277         // Try to find a good place a few times
4278         for(s32 i=0; i<1000; i++)
4279         {
4280                 s32 range = 1 + i;
4281                 // We're going to try to throw the player to this position
4282                 nodepos = v2s16(-range + (myrand()%(range*2)),
4283                                 -range + (myrand()%(range*2)));
4284                 v2s16 sectorpos = getNodeSectorPos(nodepos);
4285                 // Get sector (NOTE: Don't get because it's slow)
4286                 //m_env.getMap().emergeSector(sectorpos);
4287                 // Get ground height at point (fallbacks to heightmap function)
4288                 groundheight = map.findGroundLevel(nodepos);
4289                 // Don't go underwater
4290                 if(groundheight < WATER_LEVEL)
4291                 {
4292                         //dstream<<"-> Underwater"<<std::endl;
4293                         continue;
4294                 }
4295                 // Don't go to high places
4296                 if(groundheight > WATER_LEVEL + 4)
4297                 {
4298                         //dstream<<"-> Underwater"<<std::endl;
4299                         continue;
4300                 }
4301
4302                 // Found a good place
4303                 //dstream<<"Searched through "<<i<<" places."<<std::endl;
4304                 break;
4305         }
4306 #endif
4307         
4308         // If no suitable place was not found, go above water at least.
4309         if(groundheight < WATER_LEVEL)
4310                 groundheight = WATER_LEVEL;
4311
4312         return intToFloat(v3s16(
4313                         nodepos.X,
4314                         groundheight + 3,
4315                         nodepos.Y
4316                         ), BS);
4317 }
4318
4319 Player *Server::emergePlayer(const char *name, const char *password, u16 peer_id)
4320 {
4321         /*
4322                 Try to get an existing player
4323         */
4324         Player *player = m_env.getPlayer(name);
4325         if(player != NULL)
4326         {
4327                 // If player is already connected, cancel
4328                 if(player->peer_id != 0)
4329                 {
4330                         dstream<<"emergePlayer(): Player already connected"<<std::endl;
4331                         return NULL;
4332                 }
4333
4334                 // Got one.
4335                 player->peer_id = peer_id;
4336                 
4337                 // Reset inventory to creative if in creative mode
4338                 if(g_settings.getBool("creative_mode"))
4339                 {
4340                         // Warning: double code below
4341                         // Backup actual inventory
4342                         player->inventory_backup = new Inventory();
4343                         *(player->inventory_backup) = player->inventory;
4344                         // Set creative inventory
4345                         craft_set_creative_inventory(player);
4346                 }
4347
4348                 return player;
4349         }
4350
4351         /*
4352                 If player with the wanted peer_id already exists, cancel.
4353         */
4354         if(m_env.getPlayer(peer_id) != NULL)
4355         {
4356                 dstream<<"emergePlayer(): Player with wrong name but same"
4357                                 " peer_id already exists"<<std::endl;
4358                 return NULL;
4359         }
4360         
4361         /*
4362                 Create a new player
4363         */
4364         {
4365                 player = new ServerRemotePlayer();
4366                 //player->peer_id = c.peer_id;
4367                 //player->peer_id = PEER_ID_INEXISTENT;
4368                 player->peer_id = peer_id;
4369                 player->updateName(name);
4370                 m_authmanager.add(name);
4371                 m_authmanager.setPassword(name, password);
4372                 m_authmanager.setPrivs(name,
4373                                 stringToPrivs(g_settings.get("default_privs")));
4374
4375                 /*
4376                         Set player position
4377                 */
4378                 
4379                 dstream<<"Server: Finding spawn place for player \""
4380                                 <<player->getName()<<"\""<<std::endl;
4381
4382                 v3f pos = findSpawnPos(m_env.getServerMap());
4383
4384                 player->setPosition(pos);
4385
4386                 /*
4387                         Add player to environment
4388                 */
4389
4390                 m_env.addPlayer(player);
4391
4392                 /*
4393                         Add stuff to inventory
4394                 */
4395                 
4396                 if(g_settings.getBool("creative_mode"))
4397                 {
4398                         // Warning: double code above
4399                         // Backup actual inventory
4400                         player->inventory_backup = new Inventory();
4401                         *(player->inventory_backup) = player->inventory;
4402                         // Set creative inventory
4403                         craft_set_creative_inventory(player);
4404                 }
4405                 else if(g_settings.getBool("give_initial_stuff"))
4406                 {
4407                         craft_give_initial_stuff(player);
4408                 }
4409
4410                 return player;
4411                 
4412         } // create new player
4413 }
4414
4415 void Server::handlePeerChange(PeerChange &c)
4416 {
4417         JMutexAutoLock envlock(m_env_mutex);
4418         JMutexAutoLock conlock(m_con_mutex);
4419         
4420         if(c.type == PEER_ADDED)
4421         {
4422                 /*
4423                         Add
4424                 */
4425
4426                 // Error check
4427                 core::map<u16, RemoteClient*>::Node *n;
4428                 n = m_clients.find(c.peer_id);
4429                 // The client shouldn't already exist
4430                 assert(n == NULL);
4431
4432                 // Create client
4433                 RemoteClient *client = new RemoteClient();
4434                 client->peer_id = c.peer_id;
4435                 m_clients.insert(client->peer_id, client);
4436
4437         } // PEER_ADDED
4438         else if(c.type == PEER_REMOVED)
4439         {
4440                 /*
4441                         Delete
4442                 */
4443
4444                 // Error check
4445                 core::map<u16, RemoteClient*>::Node *n;
4446                 n = m_clients.find(c.peer_id);
4447                 // The client should exist
4448                 assert(n != NULL);
4449                 
4450                 /*
4451                         Mark objects to be not known by the client
4452                 */
4453                 RemoteClient *client = n->getValue();
4454                 // Handle objects
4455                 for(core::map<u16, bool>::Iterator
4456                                 i = client->m_known_objects.getIterator();
4457                                 i.atEnd()==false; i++)
4458                 {
4459                         // Get object
4460                         u16 id = i.getNode()->getKey();
4461                         ServerActiveObject* obj = m_env.getActiveObject(id);
4462                         
4463                         if(obj && obj->m_known_by_count > 0)
4464                                 obj->m_known_by_count--;
4465                 }
4466
4467                 // Collect information about leaving in chat
4468                 std::wstring message;
4469                 {
4470                         Player *player = m_env.getPlayer(c.peer_id);
4471                         if(player != NULL)
4472                         {
4473                                 std::wstring name = narrow_to_wide(player->getName());
4474                                 message += L"*** ";
4475                                 message += name;
4476                                 message += L" left game";
4477                                 if(c.timeout)
4478                                         message += L" (timed out)";
4479                         }
4480                 }
4481
4482                 /*// Delete player
4483                 {
4484                         m_env.removePlayer(c.peer_id);
4485                 }*/
4486
4487                 // Set player client disconnected
4488                 {
4489                         Player *player = m_env.getPlayer(c.peer_id);
4490                         if(player != NULL)
4491                                 player->peer_id = 0;
4492                 }
4493                 
4494                 // Delete client
4495                 delete m_clients[c.peer_id];
4496                 m_clients.remove(c.peer_id);
4497
4498                 // Send player info to all remaining clients
4499                 SendPlayerInfos();
4500                 
4501                 // Send leave chat message to all remaining clients
4502                 BroadcastChatMessage(message);
4503                 
4504         } // PEER_REMOVED
4505         else
4506         {
4507                 assert(0);
4508         }
4509 }
4510
4511 void Server::handlePeerChanges()
4512 {
4513         while(m_peer_change_queue.size() > 0)
4514         {
4515                 PeerChange c = m_peer_change_queue.pop_front();
4516
4517                 dout_server<<"Server: Handling peer change: "
4518                                 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4519                                 <<std::endl;
4520
4521                 handlePeerChange(c);
4522         }
4523 }
4524
4525 u64 Server::getPlayerPrivs(Player *player)
4526 {
4527         if(player==NULL)
4528                 return 0;
4529         std::string playername = player->getName();
4530         // Local player gets all privileges regardless of
4531         // what's set on their account.
4532         if(g_settings.get("name") == playername)
4533         {
4534                 return PRIV_ALL;
4535         }
4536         else
4537         {
4538                 return getPlayerAuthPrivs(playername);
4539         }
4540 }
4541
4542 void dedicated_server_loop(Server &server, bool &kill)
4543 {
4544         DSTACK(__FUNCTION_NAME);
4545         
4546         dstream<<DTIME<<std::endl;
4547         dstream<<"========================"<<std::endl;
4548         dstream<<"Running dedicated server"<<std::endl;
4549         dstream<<"========================"<<std::endl;
4550         dstream<<std::endl;
4551
4552         IntervalLimiter m_profiler_interval;
4553
4554         for(;;)
4555         {
4556                 // This is kind of a hack but can be done like this
4557                 // because server.step() is very light
4558                 {
4559                         ScopeProfiler sp(&g_profiler, "dedicated server sleep");
4560                         sleep_ms(30);
4561                 }
4562                 server.step(0.030);
4563
4564                 if(server.getShutdownRequested() || kill)
4565                 {
4566                         dstream<<DTIME<<" dedicated_server_loop(): Quitting."<<std::endl;
4567                         break;
4568                 }
4569
4570                 /*
4571                         Profiler
4572                 */
4573                 float profiler_print_interval =
4574                                 g_settings.getFloat("profiler_print_interval");
4575                 if(profiler_print_interval != 0)
4576                 {
4577                         if(m_profiler_interval.step(0.030, profiler_print_interval))
4578                         {
4579                                 dstream<<"Profiler:"<<std::endl;
4580                                 g_profiler.print(dstream);
4581                                 g_profiler.clear();
4582                         }
4583                 }
4584                 
4585                 /*
4586                         Player info
4587                 */
4588                 static int counter = 0;
4589                 counter--;
4590                 if(counter <= 0)
4591                 {
4592                         counter = 10;
4593
4594                         core::list<PlayerInfo> list = server.getPlayerInfo();
4595                         core::list<PlayerInfo>::Iterator i;
4596                         static u32 sum_old = 0;
4597                         u32 sum = PIChecksum(list);
4598                         if(sum != sum_old)
4599                         {
4600                                 dstream<<DTIME<<"Player info:"<<std::endl;
4601                                 for(i=list.begin(); i!=list.end(); i++)
4602                                 {
4603                                         i->PrintLine(&dstream);
4604                                 }
4605                         }
4606                         sum_old = sum;
4607                 }
4608         }
4609 }
4610
4611