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