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