]> git.lizzy.rs Git - minetest.git/blob - src/server.cpp
Initial files
[minetest.git] / src / server.cpp
1 /*
2 (c) 2010 Perttu Ahola <celeron55@gmail.com>
3 */
4
5 #include "server.h"
6 #include "utility.h"
7 #include <iostream>
8 #include "clientserver.h"
9 #include "map.h"
10 #include "jmutexautolock.h"
11 #include "main.h"
12 #include "constants.h"
13
14 void * ServerThread::Thread()
15 {
16         ThreadStarted();
17
18         DSTACK(__FUNCTION_NAME);
19
20         while(getRun())
21         {
22                 try{
23                         m_server->AsyncRunStep();
24                 
25                         //dout_server<<"Running m_server->Receive()"<<std::endl;
26                         m_server->Receive();
27                 }
28                 catch(con::NoIncomingDataException &e)
29                 {
30                 }
31 #if CATCH_UNHANDLED_EXCEPTIONS
32                 /*
33                         This is what has to be done in threads to get suitable debug info
34                 */
35                 catch(std::exception &e)
36                 {
37                         dstream<<std::endl<<DTIME<<"An unhandled exception occurred: "
38                                         <<e.what()<<std::endl;
39                         assert(0);
40                 }
41 #endif
42         }
43         
44
45         return NULL;
46 }
47
48 void * EmergeThread::Thread()
49 {
50         ThreadStarted();
51
52         DSTACK(__FUNCTION_NAME);
53
54         bool debug=false;
55 #if CATCH_UNHANDLED_EXCEPTIONS
56         try
57         {
58 #endif
59         
60         /*
61                 Get block info from queue, emerge them and send them
62                 to clients.
63
64                 After queue is empty, exit.
65         */
66         while(getRun())
67         {
68                 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
69                 if(qptr == NULL)
70                         break;
71                 
72                 SharedPtr<QueuedBlockEmerge> q(qptr);
73
74                 v3s16 &p = q->pos;
75                 
76                 //derr_server<<"EmergeThread::Thread(): running"<<std::endl;
77                 
78                 /*
79                         Try to emerge it from somewhere.
80
81                         If it is only wanted as optional, only loading from disk
82                         will be allowed.
83                 */
84                 
85                 /*
86                         Check if any peer wants it as non-optional. In that case it
87                         will be generated.
88
89                         Also decrement the emerge queue count in clients.
90                 */
91
92                 bool optional = true;
93
94                 {
95                         core::map<u16, u8>::Iterator i;
96                         for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
97                         {
98                                 //u16 peer_id = i.getNode()->getKey();
99
100                                 // Check flags
101                                 u8 flags = i.getNode()->getValue();
102                                 if((flags & TOSERVER_GETBLOCK_FLAG_OPTIONAL) == false)
103                                         optional = false;
104                                 
105                         }
106                 }
107
108                 /*dstream<<"EmergeThread: p="
109                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
110                                 <<"optional="<<optional<<std::endl;*/
111                 
112                 ServerMap &map = ((ServerMap&)m_server->m_env.getMap());
113                         
114                 core::map<v3s16, MapBlock*> changed_blocks;
115                 core::map<v3s16, MapBlock*> lighting_invalidated_blocks;
116
117                 MapBlock *block = NULL;
118                 bool got_block = true;
119                 core::map<v3s16, MapBlock*> modified_blocks;
120                 
121                 {//envlock
122
123                 JMutexAutoLock envlock(m_server->m_env_mutex);
124
125                 //TimeTaker timer("block emerge envlock", g_device);
126                         
127                 try{
128                         bool only_from_disk = false;
129                         
130                         if(optional)
131                                 only_from_disk = true;
132
133                         block = map.emergeBlock(
134                                         p,
135                                         only_from_disk,
136                                         changed_blocks,
137                                         lighting_invalidated_blocks);
138                         
139                         // If it is a dummy, block was not found on disk
140                         if(block->isDummy())
141                         {
142                                 //dstream<<"EmergeThread: Got a dummy block"<<std::endl;
143                                 got_block = false;
144                         }
145                 }
146                 catch(InvalidPositionException &e)
147                 {
148                         // Block not found.
149                         // This happens when position is over limit.
150                         got_block = false;
151                 }
152                 
153                 if(got_block)
154                 {
155                         if(debug && changed_blocks.size() > 0)
156                         {
157                                 dout_server<<DTIME<<"Got changed_blocks: ";
158                                 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
159                                                 i.atEnd() == false; i++)
160                                 {
161                                         MapBlock *block = i.getNode()->getValue();
162                                         v3s16 p = block->getPos();
163                                         dout_server<<"("<<p.X<<","<<p.Y<<","<<p.Z<<") ";
164                                 }
165                                 dout_server<<std::endl;
166                         }
167
168                         /*
169                                 Collect a list of blocks that have been modified in
170                                 addition to the fetched one.
171                         */
172
173                         // Add all the "changed blocks"
174                         for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
175                                         i.atEnd() == false; i++)
176                         {
177                                 MapBlock *block = i.getNode()->getValue();
178                                 modified_blocks.insert(block->getPos(), block);
179                         }
180                         
181                         //TimeTaker timer("** updateLighting", g_device);
182                         // Update lighting without locking the environment mutex,
183                         // add modified blocks to changed blocks
184                         map.updateLighting(lighting_invalidated_blocks, modified_blocks);
185                 }
186                 // If we got no block, there should be no invalidated blocks
187                 else
188                 {
189                         assert(lighting_invalidated_blocks.size() == 0);
190                 }
191
192                 }//envlock
193
194                 /*
195                         Set sent status of modified blocks on clients
196                 */
197         
198                 // NOTE: Server's clients are also behind the connection mutex
199                 JMutexAutoLock lock(m_server->m_con_mutex);
200
201                 /*
202                         Add the originally fetched block to the modified list
203                 */
204                 if(got_block)
205                 {
206                         modified_blocks.insert(p, block);
207                 }
208                 
209                 /*
210                         Set the modified blocks unsent for all the clients
211                 */
212                 
213                 for(core::map<u16, RemoteClient*>::Iterator
214                                 i = m_server->m_clients.getIterator();
215                                 i.atEnd() == false; i++)
216                 {
217                         RemoteClient *client = i.getNode()->getValue();
218                         
219                         if(modified_blocks.size() > 0)
220                         {
221                                 // Remove block from sent history
222                                 client->SetBlocksNotSent(modified_blocks);
223                         }
224                         
225                         if(q->peer_ids.find(client->peer_id) != NULL)
226                         {
227                                 // Decrement emerge queue count of client
228                                 client->BlockEmerged();
229                         }
230                 }
231                 
232         }
233 #if CATCH_UNHANDLED_EXCEPTIONS
234         }//try
235         /*
236                 This is what has to be done in threads to get suitable debug info
237         */
238         catch(std::exception &e)
239         {
240                 dstream<<std::endl<<DTIME<<"An unhandled exception occurred: "
241                                 <<e.what()<<std::endl;
242                 assert(0);
243         }
244 #endif
245
246         return NULL;
247 }
248
249 void RemoteClient::SendBlocks(Server *server, float dtime)
250 {
251         DSTACK(__FUNCTION_NAME);
252         /*
253                 Find what blocks to send to the client next, and send them.
254
255                 Throttling is based on limiting the amount of blocks "flying"
256                 at a given time.
257         */
258
259         // Can't send anything without knowing version
260         if(serialization_version == SER_FMT_VER_INVALID)
261         {
262                 dstream<<"RemoteClient::SendBlocks(): Not sending, no version."
263                                 <<std::endl;
264                 return;
265         }
266
267         {
268                 JMutexAutoLock lock(m_blocks_sending_mutex);
269                 
270                 if(m_blocks_sending.size() >= MAX_SIMULTANEOUS_BLOCK_SENDS)
271                 {
272                         //dstream<<"Not sending any blocks, Queue full."<<std::endl;
273                         return;
274                 }
275         }
276
277         Player *player = server->m_env.getPlayer(peer_id);
278
279         v3f playerpos = player->getPosition();
280         v3f playerspeed = player->getSpeed();
281
282         v3s16 center_nodepos = floatToInt(playerpos);
283
284         v3s16 center = getNodeBlockPos(center_nodepos);
285
286         /*
287                 Find out what block the player is going to next and set
288                 center to it.
289
290                 Don't react to speeds under the initial value of highest_speed
291         */
292         /*f32 highest_speed = 0.1 * BS;
293         v3s16 dir(0,0,0);
294         if(abs(playerspeed.X) > highest_speed)
295         {
296                 highest_speed = playerspeed.X;
297                 if(playerspeed.X > 0)
298                         dir = v3s16(1,0,0);
299                 else
300                         dir = v3s16(-1,0,0);
301         }
302         if(abs(playerspeed.Y) > highest_speed)
303         {
304                 highest_speed = playerspeed.Y;
305                 if(playerspeed.Y > 0)
306                         dir = v3s16(0,1,0);
307                 else
308                         dir = v3s16(0,-1,0);
309         }
310         if(abs(playerspeed.Z) > highest_speed)
311         {
312                 highest_speed = playerspeed.Z;
313                 if(playerspeed.Z > 0)
314                         dir = v3s16(0,0,1);
315                 else
316                         dir = v3s16(0,0,-1);
317         }
318
319         center += dir;*/
320         
321         /*
322                 Calculate the starting value of the block finder radius.
323
324                 The radius shall be the last used value minus the
325                 maximum moved distance.
326         */
327         /*s16 d_start = m_last_block_find_d;
328         if(max_moved >= d_start)
329         {
330                 d_start = 0;
331         }
332         else
333         {
334                 d_start -= max_moved;
335         }*/
336         
337         s16 last_nearest_unsent_d;
338         s16 d_start;
339         {
340                 JMutexAutoLock lock(m_blocks_sent_mutex);
341                 
342                 if(m_last_center != center)
343                 {
344                         m_nearest_unsent_d = 0;
345                         m_last_center = center;
346                 }
347
348                 static float reset_counter = 0;
349                 reset_counter += dtime;
350                 if(reset_counter > 5.0)
351                 {
352                         reset_counter = 0;
353                         m_nearest_unsent_d = 0;
354                 }
355
356                 last_nearest_unsent_d = m_nearest_unsent_d;
357                 
358                 d_start = m_nearest_unsent_d;
359         }
360
361         u16 maximum_simultaneous_block_sends = MAX_SIMULTANEOUS_BLOCK_SENDS;
362
363         {
364                 SharedPtr<JMutexAutoLock> lock(m_time_from_building.getLock());
365                 m_time_from_building.m_value += dtime;
366                 /*
367                         Check the time from last addNode/removeNode.
368                         Decrease send rate if player is building stuff.
369                 */
370                 if(m_time_from_building.m_value
371                                 < FULL_BLOCK_SEND_ENABLE_MIN_TIME_FROM_BUILDING)
372                 {
373                         maximum_simultaneous_block_sends
374                                 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
375                 }
376         }
377
378         // Serialization version used
379         //u8 ser_version = serialization_version;
380
381         //bool has_incomplete_blocks = false;
382         
383         /*
384                 TODO: Get this from somewhere
385                 TODO: Values more than 7 make placing and removing blocks very
386                       sluggish when the map is being generated. This is
387                           because d is looped every time from 0 to d_max if no
388                           blocks are found for sending.
389         */
390         //s16 d_max = 7;
391         s16 d_max = 8;
392
393         //TODO: Get this from somewhere (probably a bigger value)
394         s16 d_max_gen = 5;
395         
396         //dstream<<"Starting from "<<d_start<<std::endl;
397
398         for(s16 d = d_start; d <= d_max; d++)
399         {
400                 //dstream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
401                 
402                 //if(has_incomplete_blocks == false)
403                 {
404                         JMutexAutoLock lock(m_blocks_sent_mutex);
405                         /*
406                                 If m_nearest_unsent_d was changed by the EmergeThread
407                                 (it can change it to 0 through SetBlockNotSent),
408                                 update our d to it.
409                                 Else update m_nearest_unsent_d
410                         */
411                         if(m_nearest_unsent_d != last_nearest_unsent_d)
412                         {
413                                 d = m_nearest_unsent_d;
414                         }
415                         else
416                         {
417                                 m_nearest_unsent_d = d;
418                         }
419                         last_nearest_unsent_d = m_nearest_unsent_d;
420                 }
421
422                 /*
423                         Get the border/face dot coordinates of a "d-radiused"
424                         box
425                 */
426                 core::list<v3s16> list;
427                 getFacePositions(list, d);
428                 
429                 core::list<v3s16>::Iterator li;
430                 for(li=list.begin(); li!=list.end(); li++)
431                 {
432                         v3s16 p = *li + center;
433                         
434                         /*
435                                 Send throttling
436                                 - Don't allow too many simultaneous transfers
437
438                                 Also, don't send blocks that are already flying.
439                         */
440                         {
441                                 JMutexAutoLock lock(m_blocks_sending_mutex);
442                                 
443                                 if(m_blocks_sending.size()
444                                                 >= maximum_simultaneous_block_sends)
445                                 {
446                                         /*dstream<<"Not sending more blocks. Queue full. "
447                                                         <<m_blocks_sending.size()
448                                                         <<std::endl;*/
449                                         return;
450                                 }
451
452                                 if(m_blocks_sending.find(p) != NULL)
453                                         continue;
454                         }
455                         
456                         /*
457                                 Do not go over-limit
458                         */
459                         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
460                         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
461                         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
462                         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
463                         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
464                         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
465                                 continue;
466
467                         bool generate = d <= d_max_gen;
468                 
469                         // Limit the generating area vertically to half
470                         if(abs(p.Y - center.Y) > d_max_gen / 2)
471                                 generate = false;
472                         
473                         /*
474                                 Don't send already sent blocks
475                         */
476                         {
477                                 JMutexAutoLock lock(m_blocks_sent_mutex);
478                                 
479                                 if(m_blocks_sent.find(p) != NULL)
480                                         continue;
481                         }
482                                         
483                         /*
484                                 Check if map has this block
485                         */
486                         MapBlock *block = NULL;
487                         try
488                         {
489                                 block = server->m_env.getMap().getBlockNoCreate(p);
490                         }
491                         catch(InvalidPositionException &e)
492                         {
493                         }
494                         
495                         bool surely_not_found_on_disk = false;
496                         if(block != NULL)
497                         {
498                                 /*if(block->isIncomplete())
499                                 {
500                                         has_incomplete_blocks = true;
501                                         continue;
502                                 }*/
503
504                                 if(block->isDummy())
505                                 {
506                                         surely_not_found_on_disk = true;
507                                 }
508                         }
509
510                         /*
511                                 If block has been marked to not exist on disk (dummy)
512                                 and generating new ones is not wanted, skip block. TODO
513                         */
514                         if(generate == false && surely_not_found_on_disk == true)
515                         {
516                                 // get next one.
517                                 continue;
518                         }
519
520                         /*
521                                 Add inexistent block to emerge queue.
522                         */
523                         if(block == NULL || surely_not_found_on_disk)
524                         {
525                                 // Block not found.
526                                 SharedPtr<JMutexAutoLock> lock
527                                                 (m_num_blocks_in_emerge_queue.getLock());
528                                 
529                                 //TODO: Get value from somewhere
530                                 //TODO: Balance between clients
531                                 //if(server->m_emerge_queue.size() < 1)
532
533                                 // Allow only one block in emerge queue
534                                 if(m_num_blocks_in_emerge_queue.m_value == 0)
535                                 {
536                                         // Add it to the emerge queue and trigger the thread
537                                         
538                                         u8 flags = 0;
539                                         if(generate == false)
540                                                 flags |= TOSERVER_GETBLOCK_FLAG_OPTIONAL;
541                                         
542                                         {
543                                                 m_num_blocks_in_emerge_queue.m_value++;
544                                         }
545
546                                         server->m_emerge_queue.addBlock(peer_id, p, flags);
547                                         server->m_emergethread.trigger();
548                                 }
549                                 
550                                 // get next one.
551                                 continue;
552                         }
553
554                         /*
555                                 Send block
556                         */
557                         
558                         /*dstream<<"RemoteClient::SendBlocks(): d="<<d<<", p="
559                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
560                                 <<" sending queue size: "<<m_blocks_sending.size()<<std::endl;*/
561
562                         server->SendBlockNoLock(peer_id, block, serialization_version);
563                         
564                         /*
565                                 Add to history
566                         */
567                         SentBlock(p);
568                 }
569         }
570
571         // Don't add anything here. The loop breaks by returning.
572 }
573
574 void RemoteClient::SendObjectData(
575                 Server *server,
576                 float dtime,
577                 core::map<v3s16, bool> &stepped_blocks
578         )
579 {
580         DSTACK(__FUNCTION_NAME);
581
582         // Can't send anything without knowing version
583         if(serialization_version == SER_FMT_VER_INVALID)
584         {
585                 dstream<<"RemoteClient::SendObjectData(): Not sending, no version."
586                                 <<std::endl;
587                 return;
588         }
589
590         /*
591                 Send a TOCLIENT_OBJECTDATA packet.
592                 Sent as unreliable.
593
594                 u16 command
595                 u16 number of player positions
596                 for each player:
597                         v3s32 position*100
598                         v3s32 speed*100
599                         s32 pitch*100
600                         s32 yaw*100
601                 u16 count of blocks
602                 for each block:
603                         block objects
604         */
605
606         std::ostringstream os(std::ios_base::binary);
607         u8 buf[12];
608         
609         // Write command
610         writeU16(buf, TOCLIENT_OBJECTDATA);
611         os.write((char*)buf, 2);
612         
613         /*
614                 Get and write player data
615         */
616
617         core::list<Player*> players = server->m_env.getPlayers();
618
619         // Write player count
620         u16 playercount = players.size();
621         writeU16(buf, playercount);
622         os.write((char*)buf, 2);
623
624         core::list<Player*>::Iterator i;
625         for(i = players.begin();
626                         i != players.end(); i++)
627         {
628                 Player *player = *i;
629
630                 v3f pf = player->getPosition();
631                 v3f sf = player->getSpeed();
632
633                 v3s32 position_i(pf.X*100, pf.Y*100, pf.Z*100);
634                 v3s32 speed_i   (sf.X*100, sf.Y*100, sf.Z*100);
635                 s32   pitch_i   (player->getPitch() * 100);
636                 s32   yaw_i     (player->getYaw() * 100);
637                 
638                 writeU16(buf, player->peer_id);
639                 os.write((char*)buf, 2);
640                 writeV3S32(buf, position_i);
641                 os.write((char*)buf, 12);
642                 writeV3S32(buf, speed_i);
643                 os.write((char*)buf, 12);
644                 writeS32(buf, pitch_i);
645                 os.write((char*)buf, 4);
646                 writeS32(buf, yaw_i);
647                 os.write((char*)buf, 4);
648         }
649         
650         /*
651                 Get and write object data
652         */
653
654         /*
655                 Get nearby blocks.
656                 
657                 For making players to be able to build to their nearby
658                 environment (building is not possible on blocks that are not
659                 in memory):
660                 - Set blocks changed
661                 - Add blocks to emerge queue if they are not found
662         */
663
664         Player *player = server->m_env.getPlayer(peer_id);
665
666         v3f playerpos = player->getPosition();
667         v3f playerspeed = player->getSpeed();
668
669         v3s16 center_nodepos = floatToInt(playerpos);
670         v3s16 center = getNodeBlockPos(center_nodepos);
671
672         s16 d_max = ACTIVE_OBJECT_D_BLOCKS;
673
674         core::map<v3s16, MapBlock*> blocks;
675
676         for(s16 d = 0; d <= d_max; d++)
677         {
678                 core::list<v3s16> list;
679                 getFacePositions(list, d);
680                 
681                 core::list<v3s16>::Iterator li;
682                 for(li=list.begin(); li!=list.end(); li++)
683                 {
684                         v3s16 p = *li + center;
685
686                         /*
687                                 Ignore blocks that haven't been sent to the client
688                         */
689                         {
690                                 JMutexAutoLock sentlock(m_blocks_sent_mutex);
691                                 if(m_blocks_sent.find(p) == NULL)
692                                         continue;
693                         }
694
695                         try
696                         {
697
698                         // Get block
699                         MapBlock *block = server->m_env.getMap().getBlockNoCreate(p);
700
701                         // Step block if not in stepped_blocks and add to stepped_blocks
702                         if(stepped_blocks.find(p) == NULL)
703                         {
704                                 block->stepObjects(dtime, true);
705                                 stepped_blocks.insert(p, true);
706                                 block->setChangedFlag();
707                         }
708                         
709                         // Add block to queue
710                         blocks.insert(p, block);
711                         
712                         } //try
713                         catch(InvalidPositionException &e)
714                         {
715                                 // Not in memory
716                                 // Add it to the emerge queue and trigger the thread.
717                                 // Fetch the block only if it is on disk.
718                                 
719                                 // Grab and increment counter
720                                 SharedPtr<JMutexAutoLock> lock
721                                                 (m_num_blocks_in_emerge_queue.getLock());
722                                 m_num_blocks_in_emerge_queue.m_value++;
723                                 
724                                 // Add to queue as an anonymous fetch from disk
725                                 u8 flags = TOSERVER_GETBLOCK_FLAG_OPTIONAL;
726                                 server->m_emerge_queue.addBlock(0, p, flags);
727                                 server->m_emergethread.trigger();
728                         }
729                 }
730         }
731
732         /*
733                 Write objects
734         */
735
736         u16 blockcount = blocks.size();
737
738         // Write block count
739         writeU16(buf, blockcount);
740         os.write((char*)buf, 2);
741         
742         for(core::map<v3s16, MapBlock*>::Iterator
743                         i = blocks.getIterator();
744                         i.atEnd() == false; i++)
745         {
746                 v3s16 p = i.getNode()->getKey();
747                 // Write blockpos
748                 writeV3S16(buf, p);
749                 os.write((char*)buf, 6);
750                 // Write objects
751                 MapBlock *block = i.getNode()->getValue();
752                 block->serializeObjects(os, serialization_version);
753         }
754         
755         /*
756                 Send data
757         */
758         
759         // Make data buffer
760         std::string s = os.str();
761         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
762         // Send as unreliable
763         server->m_con.Send(peer_id, 0, data, false);
764 }
765
766 void RemoteClient::GotBlock(v3s16 p)
767 {
768         JMutexAutoLock lock(m_blocks_sending_mutex);
769         JMutexAutoLock lock2(m_blocks_sent_mutex);
770         if(m_blocks_sending.find(p) != NULL)
771                 m_blocks_sending.remove(p);
772         else
773                 dstream<<"RemoteClient::GotBlock(): Didn't find in"
774                                 " m_blocks_sending"<<std::endl;
775         m_blocks_sent.insert(p, true);
776 }
777
778 void RemoteClient::SentBlock(v3s16 p)
779 {
780         JMutexAutoLock lock(m_blocks_sending_mutex);
781         if(m_blocks_sending.size() > 15)
782         {
783                 dstream<<"RemoteClient::SentBlock(): "
784                                 <<"m_blocks_sending.size()="
785                                 <<m_blocks_sending.size()<<std::endl;
786         }
787         if(m_blocks_sending.find(p) == NULL)
788                 m_blocks_sending.insert(p, 0.0);
789         else
790                 dstream<<"RemoteClient::SentBlock(): Sent block"
791                                 " already in m_blocks_sending"<<std::endl;
792 }
793
794 void RemoteClient::SetBlockNotSent(v3s16 p)
795 {
796         JMutexAutoLock sendinglock(m_blocks_sending_mutex);
797         JMutexAutoLock sentlock(m_blocks_sent_mutex);
798
799         m_nearest_unsent_d = 0;
800         
801         if(m_blocks_sending.find(p) != NULL)
802                 m_blocks_sending.remove(p);
803         if(m_blocks_sent.find(p) != NULL)
804                 m_blocks_sent.remove(p);
805 }
806
807 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
808 {
809         JMutexAutoLock sendinglock(m_blocks_sending_mutex);
810         JMutexAutoLock sentlock(m_blocks_sent_mutex);
811
812         m_nearest_unsent_d = 0;
813         
814         for(core::map<v3s16, MapBlock*>::Iterator
815                         i = blocks.getIterator();
816                         i.atEnd()==false; i++)
817         {
818                 v3s16 p = i.getNode()->getKey();
819
820                 if(m_blocks_sending.find(p) != NULL)
821                         m_blocks_sending.remove(p);
822                 if(m_blocks_sent.find(p) != NULL)
823                         m_blocks_sent.remove(p);
824         }
825 }
826
827 void RemoteClient::BlockEmerged()
828 {
829         SharedPtr<JMutexAutoLock> lock(m_num_blocks_in_emerge_queue.getLock());
830         assert(m_num_blocks_in_emerge_queue.m_value > 0);
831         m_num_blocks_in_emerge_queue.m_value--;
832 }
833
834 /*void RemoteClient::RunSendingTimeouts(float dtime, float timeout)
835 {
836         JMutexAutoLock sendinglock(m_blocks_sending_mutex);
837         
838         core::list<v3s16> remove_queue;
839         for(core::map<v3s16, float>::Iterator
840                         i = m_blocks_sending.getIterator();
841                         i.atEnd()==false; i++)
842         {
843                 v3s16 p = i.getNode()->getKey();
844                 float t = i.getNode()->getValue();
845                 t += dtime;
846                 i.getNode()->setValue(t);
847
848                 if(t > timeout)
849                 {
850                         remove_queue.push_back(p);
851                 }
852         }
853         for(core::list<v3s16>::Iterator
854                         i = remove_queue.begin();
855                         i != remove_queue.end(); i++)
856         {
857                 m_blocks_sending.remove(*i);
858         }
859 }*/
860
861 /*
862         PlayerInfo
863 */
864
865 PlayerInfo::PlayerInfo()
866 {
867         name[0] = 0;
868 }
869
870 void PlayerInfo::PrintLine(std::ostream *s)
871 {
872         (*s)<<id<<": \""<<name<<"\" ("
873                         <<position.X<<","<<position.Y
874                         <<","<<position.Z<<") ";
875         address.print(s);
876         (*s)<<" avg_rtt="<<avg_rtt;
877         (*s)<<std::endl;
878 }
879
880 u32 PIChecksum(core::list<PlayerInfo> &l)
881 {
882         core::list<PlayerInfo>::Iterator i;
883         u32 checksum = 1;
884         u32 a = 10;
885         for(i=l.begin(); i!=l.end(); i++)
886         {
887                 checksum += a * (i->id+1);
888                 checksum ^= 0x435aafcd;
889                 a *= 10;
890         }
891         return checksum;
892 }
893
894 /*
895         Server
896 */
897
898 Server::Server(
899                 std::string mapsavedir,
900                 bool creative_mode,
901                 MapgenParams mapgen_params
902         ):
903         m_env(new ServerMap(mapsavedir, mapgen_params), dout_server),
904         m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
905         m_thread(this),
906         m_emergethread(this),
907         m_creative_mode(creative_mode)
908 {
909         m_env_mutex.Init();
910         m_con_mutex.Init();
911         m_step_dtime_mutex.Init();
912         m_step_dtime = 0.0;
913 }
914
915 Server::~Server()
916 {
917         // Stop threads
918         stop();
919
920         JMutexAutoLock clientslock(m_con_mutex);
921
922         for(core::map<u16, RemoteClient*>::Iterator
923                 i = m_clients.getIterator();
924                 i.atEnd() == false; i++)
925         {
926                 u16 peer_id = i.getNode()->getKey();
927
928                 // Delete player
929                 {
930                         JMutexAutoLock envlock(m_env_mutex);
931                         m_env.removePlayer(peer_id);
932                 }
933                 
934                 // Delete client
935                 delete i.getNode()->getValue();
936         }
937 }
938
939 void Server::start(unsigned short port)
940 {
941         DSTACK(__FUNCTION_NAME);
942         // Stop thread if already running
943         m_thread.stop();
944         
945         // Initialize connection
946         m_con.setTimeoutMs(50);
947         m_con.Serve(port);
948
949         // Start thread
950         m_thread.setRun(true);
951         m_thread.Start();
952         
953         dout_server<<"Server started on port "<<port<<std::endl;
954 }
955
956 void Server::stop()
957 {
958         DSTACK(__FUNCTION_NAME);
959         // Stop threads (set run=false first so both start stopping)
960         m_thread.setRun(false);
961         m_emergethread.setRun(false);
962         m_thread.stop();
963         m_emergethread.stop();
964         
965         dout_server<<"Server threads stopped"<<std::endl;
966 }
967
968 void Server::step(float dtime)
969 {
970         DSTACK(__FUNCTION_NAME);
971         // Limit a bit
972         if(dtime > 2.0)
973                 dtime = 2.0;
974         {
975                 JMutexAutoLock lock(m_step_dtime_mutex);
976                 m_step_dtime += dtime;
977         }
978 }
979
980 void Server::AsyncRunStep()
981 {
982         DSTACK(__FUNCTION_NAME);
983         float dtime;
984         {
985                 JMutexAutoLock lock1(m_step_dtime_mutex);
986                 dtime = m_step_dtime;
987                 if(dtime < 0.001)
988                         return;
989                 m_step_dtime = 0.0;
990         }
991         
992         //dstream<<"Server steps "<<dtime<<std::endl;
993         
994         //dstream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
995         {
996                 // Has to be locked for peerAdded/Removed
997                 JMutexAutoLock lock1(m_env_mutex);
998                 // Process connection's timeouts
999                 JMutexAutoLock lock2(m_con_mutex);
1000                 m_con.RunTimeouts(dtime);
1001         }
1002         {
1003                 // Step environment
1004                 // This also runs Map's timers
1005                 JMutexAutoLock lock(m_env_mutex);
1006                 m_env.step(dtime);
1007         }
1008         
1009         /*
1010                 Do background stuff
1011         */
1012         
1013         // Periodically print some info
1014         {
1015                 static float counter = 0.0;
1016                 counter += dtime;
1017                 if(counter >= 30.0)
1018                 {
1019                         counter = 0.0;
1020
1021                         JMutexAutoLock lock2(m_con_mutex);
1022
1023                         for(core::map<u16, RemoteClient*>::Iterator
1024                                 i = m_clients.getIterator();
1025                                 i.atEnd() == false; i++)
1026                         {
1027                                 //u16 peer_id = i.getNode()->getKey();
1028                                 RemoteClient *client = i.getNode()->getValue();
1029                                 client->PrintInfo(std::cout);
1030                         }
1031                 }
1032         }
1033
1034         // Run time- and client- related stuff
1035         // NOTE: If you intend to add something here, check that it
1036         // doesn't fit in RemoteClient::SendBlocks for exampel.
1037         /*{
1038                 // Clients are behind connection lock
1039                 JMutexAutoLock lock(m_con_mutex);
1040
1041                 for(core::map<u16, RemoteClient*>::Iterator
1042                         i = m_clients.getIterator();
1043                         i.atEnd() == false; i++)
1044                 {
1045                         RemoteClient *client = i.getNode()->getValue();
1046                         //con::Peer *peer = m_con.GetPeer(client->peer_id);
1047                         //client->RunSendingTimeouts(dtime, peer->resend_timeout);
1048                 }
1049         }*/
1050
1051         // Send blocks to clients
1052         SendBlocks(dtime);
1053         
1054         // Send object positions
1055         {
1056                 static float counter = 0.0;
1057                 counter += dtime;
1058                 //TODO: Get value from somewhere
1059                 if(counter >= 0.1)
1060                 {
1061                         JMutexAutoLock lock1(m_env_mutex);
1062                         JMutexAutoLock lock2(m_con_mutex);
1063                         SendObjectData(counter);
1064
1065                         counter = 0.0;
1066                 }
1067         }
1068
1069         {
1070                 // Save map
1071                 static float counter = 0.0;
1072                 counter += dtime;
1073                 if(counter >= SERVER_MAP_SAVE_INTERVAL)
1074                 {
1075                         counter = 0.0;
1076
1077                         JMutexAutoLock lock(m_env_mutex);
1078                         // Save only changed parts
1079                         m_env.getMap().save(true);
1080                 }
1081         }
1082 }
1083
1084 void Server::Receive()
1085 {
1086         DSTACK(__FUNCTION_NAME);
1087         u32 data_maxsize = 10000;
1088         Buffer<u8> data(data_maxsize);
1089         u16 peer_id;
1090         u32 datasize;
1091         try{
1092                 {
1093                         JMutexAutoLock lock(m_con_mutex);
1094                         datasize = m_con.Receive(peer_id, *data, data_maxsize);
1095                 }
1096                 ProcessData(*data, datasize, peer_id);
1097         }
1098         catch(con::InvalidIncomingDataException &e)
1099         {
1100                 derr_server<<"Server::Receive(): "
1101                                 "InvalidIncomingDataException: what()="
1102                                 <<e.what()<<std::endl;
1103         }
1104         catch(con::PeerNotFoundException &e)
1105         {
1106                 //NOTE: This is not needed anymore
1107                 
1108                 // The peer has been disconnected.
1109                 // Find the associated player and remove it.
1110
1111                 /*JMutexAutoLock envlock(m_env_mutex);
1112
1113                 dout_server<<"ServerThread: peer_id="<<peer_id
1114                                 <<" has apparently closed connection. "
1115                                 <<"Removing player."<<std::endl;
1116
1117                 m_env.removePlayer(peer_id);*/
1118         }
1119 }
1120
1121 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1122 {
1123         DSTACK(__FUNCTION_NAME);
1124         // Environment is locked first.
1125         JMutexAutoLock envlock(m_env_mutex);
1126         JMutexAutoLock conlock(m_con_mutex);
1127         
1128         con::Peer *peer;
1129         try{
1130                 peer = m_con.GetPeer(peer_id);
1131         }
1132         catch(con::PeerNotFoundException &e)
1133         {
1134                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: peer "
1135                                 <<peer_id<<" not found"<<std::endl;
1136                 return;
1137         }
1138         
1139         //u8 peer_ser_ver = peer->serialization_version;
1140         u8 peer_ser_ver = getClient(peer->id)->serialization_version;
1141
1142         try
1143         {
1144
1145         if(datasize < 2)
1146                 return;
1147
1148         ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1149         
1150         if(command == TOSERVER_INIT)
1151         {
1152                 // [0] u16 TOSERVER_INIT
1153                 // [2] u8 SER_FMT_VER_HIGHEST
1154                 // [3] u8[20] player_name
1155
1156                 if(datasize < 3)
1157                         return;
1158
1159                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT from "
1160                                 <<peer->id<<std::endl;
1161
1162                 // First byte after command is maximum supported
1163                 // serialization version
1164                 u8 client_max = data[2];
1165                 u8 our_max = SER_FMT_VER_HIGHEST;
1166                 // Use the highest version supported by both
1167                 u8 deployed = core::min_(client_max, our_max);
1168                 // If it's lower than the lowest supported, give up.
1169                 if(deployed < SER_FMT_VER_LOWEST)
1170                         deployed = SER_FMT_VER_INVALID;
1171
1172                 //peer->serialization_version = deployed;
1173                 getClient(peer->id)->pending_serialization_version = deployed;
1174
1175                 if(deployed == SER_FMT_VER_INVALID)
1176                 {
1177                         derr_server<<DTIME<<"Server: Cannot negotiate "
1178                                         "serialization version with peer "
1179                                         <<peer_id<<std::endl;
1180                         return;
1181                 }
1182
1183                 /*
1184                         Set up player
1185                 */
1186
1187                 Player *player = m_env.getPlayer(peer_id);
1188
1189                 // Check if player doesn't exist
1190                 if(player == NULL)
1191                         throw con::InvalidIncomingDataException
1192                                 ("Server::ProcessData(): INIT: Player doesn't exist");
1193
1194                 // update name if it was supplied
1195                 if(datasize >= 20+3)
1196                 {
1197                         data[20+3-1] = 0;
1198                         player->updateName((const char*)&data[3]);
1199                 }
1200
1201                 // Now answer with a TOCLIENT_INIT
1202                 
1203                 SharedBuffer<u8> reply(2+1+6);
1204                 writeU16(&reply[0], TOCLIENT_INIT);
1205                 writeU8(&reply[2], deployed);
1206                 writeV3S16(&reply[3], floatToInt(player->getPosition()+v3f(0,BS/2,0)));
1207                 // Send as reliable
1208                 m_con.Send(peer_id, 0, reply, true);
1209
1210                 return;
1211         }
1212         if(command == TOSERVER_INIT2)
1213         {
1214                 derr_server<<DTIME<<"Server: Got TOSERVER_INIT2 from "
1215                                 <<peer->id<<std::endl;
1216
1217
1218                 getClient(peer->id)->serialization_version
1219                                 = getClient(peer->id)->pending_serialization_version;
1220
1221                 /*
1222                         Send some initialization data
1223                 */
1224                 
1225                 // Send player info to all players
1226                 SendPlayerInfos();
1227
1228                 // Send inventory to player
1229                 SendInventory(peer->id);
1230
1231                 return;
1232         }
1233
1234         if(peer_ser_ver == SER_FMT_VER_INVALID)
1235         {
1236                 derr_server<<DTIME<<"Server::ProcessData(): Cancelling: Peer"
1237                                 " serialization format invalid or not initialized."
1238                                 " Skipping incoming command="<<command<<std::endl;
1239                 return;
1240         }
1241         
1242         Player *player = m_env.getPlayer(peer_id);
1243
1244         if(player == NULL){
1245                 derr_server<<"Server::ProcessData(): Cancelling: "
1246                                 "No player for peer_id="<<peer_id
1247                                 <<std::endl;
1248                 return;
1249         }
1250         if(command == TOSERVER_PLAYERPOS)
1251         {
1252                 if(datasize < 2+12+12+4+4)
1253                         return;
1254         
1255                 u32 start = 0;
1256                 v3s32 ps = readV3S32(&data[start+2]);
1257                 v3s32 ss = readV3S32(&data[start+2+12]);
1258                 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1259                 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1260                 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1261                 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1262                 pitch = wrapDegrees(pitch);
1263                 yaw = wrapDegrees(yaw);
1264                 player->setPosition(position);
1265                 player->setSpeed(speed);
1266                 player->setPitch(pitch);
1267                 player->setYaw(yaw);
1268                 
1269                 /*dout_server<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1270                                 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1271                                 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1272         }
1273         else if(command == TOSERVER_GOTBLOCKS)
1274         {
1275                 if(datasize < 2+1)
1276                         return;
1277                 
1278                 /*
1279                         [0] u16 command
1280                         [2] u8 count
1281                         [3] v3s16 pos_0
1282                         [3+6] v3s16 pos_1
1283                         ...
1284                 */
1285
1286                 u16 count = data[2];
1287                 for(u16 i=0; i<count; i++)
1288                 {
1289                         if((s16)datasize < 2+1+(i+1)*6)
1290                                 throw con::InvalidIncomingDataException
1291                                         ("GOTBLOCKS length is too short");
1292                         v3s16 p = readV3S16(&data[2+1+i*6]);
1293                         /*dstream<<"Server: GOTBLOCKS ("
1294                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1295                         RemoteClient *client = getClient(peer_id);
1296                         client->GotBlock(p);
1297                 }
1298         }
1299         else if(command == TOSERVER_DELETEDBLOCKS)
1300         {
1301                 if(datasize < 2+1)
1302                         return;
1303                 
1304                 /*
1305                         [0] u16 command
1306                         [2] u8 count
1307                         [3] v3s16 pos_0
1308                         [3+6] v3s16 pos_1
1309                         ...
1310                 */
1311
1312                 u16 count = data[2];
1313                 for(u16 i=0; i<count; i++)
1314                 {
1315                         if((s16)datasize < 2+1+(i+1)*6)
1316                                 throw con::InvalidIncomingDataException
1317                                         ("DELETEDBLOCKS length is too short");
1318                         v3s16 p = readV3S16(&data[2+1+i*6]);
1319                         /*dstream<<"Server: DELETEDBLOCKS ("
1320                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1321                         RemoteClient *client = getClient(peer_id);
1322                         client->SetBlockNotSent(p);
1323                 }
1324         }
1325         else if(command == TOSERVER_CLICK_OBJECT)
1326         {
1327                 if(datasize < 13)
1328                         return;
1329
1330                 /*
1331                         [0] u16 command
1332                         [2] u8 button (0=left, 1=right)
1333                         [3] v3s16 block
1334                         [9] s16 id
1335                         [11] u16 item
1336                 */
1337                 u8 button = readU8(&data[2]);
1338                 v3s16 p;
1339                 p.X = readS16(&data[3]);
1340                 p.Y = readS16(&data[5]);
1341                 p.Z = readS16(&data[7]);
1342                 s16 id = readS16(&data[9]);
1343                 //u16 item_i = readU16(&data[11]);
1344
1345                 MapBlock *block = NULL;
1346                 try
1347                 {
1348                         block = m_env.getMap().getBlockNoCreate(p);
1349                 }
1350                 catch(InvalidPositionException &e)
1351                 {
1352                         derr_server<<"PICK_OBJECT block not found"<<std::endl;
1353                         return;
1354                 }
1355
1356                 MapBlockObject *obj = block->getObject(id);
1357
1358                 if(obj == NULL)
1359                 {
1360                         derr_server<<"PICK_OBJECT object not found"<<std::endl;
1361                         return;
1362                 }
1363
1364                 //TODO: Check that object is reasonably close
1365                 
1366                 // Left click
1367                 if(button == 0)
1368                 {
1369                         if(m_creative_mode == false)
1370                         {
1371                         
1372                                 // Skip if inventory has no free space
1373                                 if(player->inventory.getUsedSlots() == player->inventory.getSize())
1374                                 {
1375                                         dout_server<<"Player inventory has no free space"<<std::endl;
1376                                         return;
1377                                 }
1378                         
1379                                 // Add to inventory and send inventory
1380                                 InventoryItem *item = new MapBlockObjectItem
1381                                                 (obj->getInventoryString());
1382                                 player->inventory.addItem(item);
1383                                 SendInventory(player->peer_id);
1384                         }
1385
1386                         // Remove from block
1387                         block->removeObject(id);
1388                 }
1389         }
1390         else if(command == TOSERVER_CLICK_GROUND)
1391         {
1392                 if(datasize < 17)
1393                         return;
1394                 /*
1395                         length: 17
1396                         [0] u16 command
1397                         [2] u8 button (0=left, 1=right)
1398                         [3] v3s16 nodepos_undersurface
1399                         [9] v3s16 nodepos_abovesurface
1400                         [15] u16 item
1401                 */
1402                 u8 button = readU8(&data[2]);
1403                 v3s16 p_under;
1404                 p_under.X = readS16(&data[3]);
1405                 p_under.Y = readS16(&data[5]);
1406                 p_under.Z = readS16(&data[7]);
1407                 v3s16 p_over;
1408                 p_over.X = readS16(&data[9]);
1409                 p_over.Y = readS16(&data[11]);
1410                 p_over.Z = readS16(&data[13]);
1411                 u16 item_i = readU16(&data[15]);
1412
1413                 //TODO: Check that target is reasonably close
1414                 
1415                 /*
1416                         Left button digs ground
1417                 */
1418                 if(button == 0)
1419                 {
1420
1421                         core::map<v3s16, MapBlock*> modified_blocks;
1422
1423                         u8 material;
1424
1425                         try
1426                         {
1427                                 // Get material at position
1428                                 material = m_env.getMap().getNode(p_under).d;
1429                                 // If it's air, do nothing
1430                                 if(material == MATERIAL_AIR)
1431                                 {
1432                                         return;
1433                                 }
1434                                 // Otherwise remove it
1435                                 m_env.getMap().removeNodeAndUpdate(p_under, modified_blocks);
1436                         }
1437                         catch(InvalidPositionException &e)
1438                         {
1439                                 derr_server<<"Server: Ignoring REMOVENODE: Node not found"
1440                                                 <<std::endl;
1441                                 return;
1442                         }
1443                         
1444                         // Reset build time counter
1445                         getClient(peer->id)->m_time_from_building.set(0.0);
1446                         
1447                         // Create packet
1448                         u32 replysize = 8;
1449                         SharedBuffer<u8> reply(replysize);
1450                         writeU16(&reply[0], TOCLIENT_REMOVENODE);
1451                         writeS16(&reply[2], p_under.X);
1452                         writeS16(&reply[4], p_under.Y);
1453                         writeS16(&reply[6], p_under.Z);
1454                         // Send as reliable
1455                         m_con.SendToAll(0, reply, true);
1456                         
1457                         if(m_creative_mode == false)
1458                         {
1459                                 // Add to inventory and send inventory
1460                                 InventoryItem *item = new MaterialItem(material, 1);
1461                                 player->inventory.addItem(item);
1462                                 SendInventory(player->peer_id);
1463                         }
1464
1465                 } // button == 0
1466                 /*
1467                         Right button places blocks and stuff
1468                 */
1469                 else if(button == 1)
1470                 {
1471
1472                         // Get item
1473                         InventoryItem *item = player->inventory.getItem(item_i);
1474                         
1475                         // If there is no item, it is not possible to add it anywhere
1476                         if(item == NULL)
1477                                 return;
1478                         
1479                         /*
1480                                 Handle material items
1481                         */
1482                         if(std::string("MaterialItem") == item->getName())
1483                         {
1484                                 MaterialItem *mitem = (MaterialItem*)item;
1485                                 
1486                                 MapNode n;
1487                                 n.d = mitem->getMaterial();
1488
1489                                 try{
1490                                         // Don't add a node if there isn't air
1491                                         MapNode n2 = m_env.getMap().getNode(p_over);
1492                                         if(n2.d != MATERIAL_AIR)
1493                                                 return;
1494
1495                                         core::map<v3s16, MapBlock*> modified_blocks;
1496                                         m_env.getMap().addNodeAndUpdate(p_over, n, modified_blocks);
1497                                 }
1498                                 catch(InvalidPositionException &e)
1499                                 {
1500                                         derr_server<<"Server: Ignoring ADDNODE: Node not found"
1501                                                         <<std::endl;
1502                                         return;
1503                                 }
1504
1505                                 // Reset build time counter
1506                                 getClient(peer->id)->m_time_from_building.set(0.0);
1507                                 
1508                                 if(m_creative_mode == false)
1509                                 {
1510                                         // Remove from inventory and send inventory
1511                                         if(mitem->getCount() == 1)
1512                                                 player->inventory.deleteItem(item_i);
1513                                         else
1514                                                 mitem->remove(1);
1515                                         // Send inventory
1516                                         SendInventory(peer_id);
1517                                 }
1518                                 
1519                                 // Create packet
1520                                 u32 replysize = 8 + MapNode::serializedLength(peer_ser_ver);
1521                                 SharedBuffer<u8> reply(replysize);
1522                                 writeU16(&reply[0], TOCLIENT_ADDNODE);
1523                                 writeS16(&reply[2], p_over.X);
1524                                 writeS16(&reply[4], p_over.Y);
1525                                 writeS16(&reply[6], p_over.Z);
1526                                 n.serialize(&reply[8], peer_ser_ver);
1527                                 // Send as reliable
1528                                 m_con.SendToAll(0, reply, true);
1529                         }
1530                         /*
1531                                 Handle block object items
1532                         */
1533                         else if(std::string("MBOItem") == item->getName())
1534                         {
1535                                 MapBlockObjectItem *oitem = (MapBlockObjectItem*)item;
1536
1537                                 /*dout_server<<"Trying to place a MapBlockObjectItem: "
1538                                                 "inventorystring=\""
1539                                                 <<oitem->getInventoryString()
1540                                                 <<"\""<<std::endl;*/
1541
1542                                 v3s16 blockpos = getNodeBlockPos(p_over);
1543
1544                                 MapBlock *block = NULL;
1545                                 try
1546                                 {
1547                                         block = m_env.getMap().getBlockNoCreate(blockpos);
1548                                 }
1549                                 catch(InvalidPositionException &e)
1550                                 {
1551                                         derr_server<<"Error while placing object: "
1552                                                         "block not found"<<std::endl;
1553                                         return;
1554                                 }
1555
1556                                 v3s16 block_pos_i_on_map = block->getPosRelative();
1557                                 v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map);
1558
1559                                 v3f pos = intToFloat(p_over);
1560                                 pos -= block_pos_f_on_map;
1561                                 
1562                                 /*dout_server<<"pos="
1563                                                 <<"("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1564                                                 <<std::endl;*/
1565
1566
1567                                 MapBlockObject *obj = oitem->createObject
1568                                                 (pos, player->getYaw(), player->getPitch());
1569
1570                                 if(obj == NULL)
1571                                         derr_server<<"WARNING: oitem created NULL object"
1572                                                         <<std::endl;
1573
1574                                 block->addObject(obj);
1575
1576                                 //dout_server<<"Placed object"<<std::endl;
1577
1578                                 if(m_creative_mode == false)
1579                                 {
1580                                         // Remove from inventory and send inventory
1581                                         player->inventory.deleteItem(item_i);
1582                                         // Send inventory
1583                                         SendInventory(peer_id);
1584                                 }
1585                         }
1586
1587                 } // button == 1
1588                 /*
1589                         Catch invalid buttons
1590                 */
1591                 else
1592                 {
1593                         derr_server<<"WARNING: Server: Invalid button "
1594                                         <<button<<std::endl;
1595                 }
1596         }
1597         else if(command == TOSERVER_RELEASE)
1598         {
1599                 if(datasize < 3)
1600                         return;
1601                 /*
1602                         length: 3
1603                         [0] u16 command
1604                         [2] u8 button
1605                 */
1606                 //TODO
1607         }
1608         else if(command == TOSERVER_SIGNTEXT)
1609         {
1610                 /*
1611                         u16 command
1612                         v3s16 blockpos
1613                         s16 id
1614                         u16 textlen
1615                         textdata
1616                 */
1617                 std::string datastring((char*)&data[2], datasize-2);
1618                 std::istringstream is(datastring, std::ios_base::binary);
1619                 u8 buf[6];
1620                 // Read stuff
1621                 is.read((char*)buf, 6);
1622                 v3s16 blockpos = readV3S16(buf);
1623                 is.read((char*)buf, 2);
1624                 s16 id = readS16(buf);
1625                 is.read((char*)buf, 2);
1626                 u16 textlen = readU16(buf);
1627                 std::string text;
1628                 for(u16 i=0; i<textlen; i++)
1629                 {
1630                         is.read((char*)buf, 1);
1631                         text += (char)buf[0];
1632                 }
1633
1634                 MapBlock *block = NULL;
1635                 try
1636                 {
1637                         block = m_env.getMap().getBlockNoCreate(blockpos);
1638                 }
1639                 catch(InvalidPositionException &e)
1640                 {
1641                         derr_server<<"Error while setting sign text: "
1642                                         "block not found"<<std::endl;
1643                         return;
1644                 }
1645
1646                 MapBlockObject *obj = block->getObject(id);
1647                 if(obj == NULL)
1648                 {
1649                         derr_server<<"Error while setting sign text: "
1650                                         "object not found"<<std::endl;
1651                         return;
1652                 }
1653                 
1654                 if(obj->getTypeId() != MAPBLOCKOBJECT_TYPE_SIGN)
1655                 {
1656                         derr_server<<"Error while setting sign text: "
1657                                         "object is not a sign"<<std::endl;
1658                         return;
1659                 }
1660
1661                 ((SignObject*)obj)->setText(text);
1662
1663                 obj->getBlock()->setChangedFlag();
1664         }
1665         else
1666         {
1667                 derr_server<<"WARNING: Server::ProcessData(): Ignoring "
1668                                 "unknown command "<<command<<std::endl;
1669         }
1670         
1671         } //try
1672         catch(SendFailedException &e)
1673         {
1674                 derr_server<<"Server::ProcessData(): SendFailedException: "
1675                                 <<"what="<<e.what()
1676                                 <<std::endl;
1677         }
1678 }
1679
1680 /*void Server::Send(u16 peer_id, u16 channelnum,
1681                 SharedBuffer<u8> data, bool reliable)
1682 {
1683         JMutexAutoLock lock(m_con_mutex);
1684         m_con.Send(peer_id, channelnum, data, reliable);
1685 }*/
1686
1687 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
1688 {
1689         DSTACK(__FUNCTION_NAME);
1690         /*
1691                 Create a packet with the block in the right format
1692         */
1693         
1694         std::ostringstream os(std::ios_base::binary);
1695         block->serialize(os, ver);
1696         std::string s = os.str();
1697         SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
1698
1699         u32 replysize = 8 + blockdata.getSize();
1700         SharedBuffer<u8> reply(replysize);
1701         v3s16 p = block->getPos();
1702         writeU16(&reply[0], TOCLIENT_BLOCKDATA);
1703         writeS16(&reply[2], p.X);
1704         writeS16(&reply[4], p.Y);
1705         writeS16(&reply[6], p.Z);
1706         memcpy(&reply[8], *blockdata, blockdata.getSize());
1707         
1708         /*
1709                 Send packet
1710         */
1711         m_con.Send(peer_id, 1, reply, true);
1712 }
1713
1714 /*void Server::SendBlock(u16 peer_id, MapBlock *block, u8 ver)
1715 {
1716         JMutexAutoLock conlock(m_con_mutex);
1717         
1718         SendBlockNoLock(peer_id, block, ver);
1719 }*/
1720
1721 #if 0
1722 void Server::SendSectorMeta(u16 peer_id, core::list<v2s16> ps, u8 ver)
1723 {
1724         DSTACK(__FUNCTION_NAME);
1725         dstream<<"Server sending sector meta of "
1726                         <<ps.getSize()<<" sectors"<<std::endl;
1727
1728         core::list<v2s16>::Iterator i = ps.begin();
1729         core::list<v2s16> sendlist;
1730         for(;;)
1731         {
1732                 if(sendlist.size() == 255 || i == ps.end())
1733                 {
1734                         if(sendlist.size() == 0)
1735                                 break;
1736                         /*
1737                                 [0] u16 command
1738                                 [2] u8 sector count
1739                                 [3...] v2s16 pos + sector metadata
1740                         */
1741                         std::ostringstream os(std::ios_base::binary);
1742                         u8 buf[4];
1743
1744                         writeU16(buf, TOCLIENT_SECTORMETA);
1745                         os.write((char*)buf, 2);
1746
1747                         writeU8(buf, sendlist.size());
1748                         os.write((char*)buf, 1);
1749
1750                         for(core::list<v2s16>::Iterator
1751                                         j = sendlist.begin();
1752                                         j != sendlist.end(); j++)
1753                         {
1754                                 // Write position
1755                                 writeV2S16(buf, *j);
1756                                 os.write((char*)buf, 4);
1757                                 
1758                                 /*
1759                                         Write ClientMapSector metadata
1760                                 */
1761
1762                                 /*
1763                                         [0] u8 serialization version
1764                                         [1] s16 corners[0]
1765                                         [3] s16 corners[1]
1766                                         [5] s16 corners[2]
1767                                         [7] s16 corners[3]
1768                                         size = 9
1769                                         
1770                                         In which corners are in these positions
1771                                         v2s16(0,0),
1772                                         v2s16(1,0),
1773                                         v2s16(1,1),
1774                                         v2s16(0,1),
1775                                 */
1776
1777                                 // Write version
1778                                 writeU8(buf, ver);
1779                                 os.write((char*)buf, 1);
1780
1781                                 // Write corners
1782                                 // TODO: Get real values
1783                                 s16 corners[4];
1784                                 ((ServerMap&)m_env.getMap()).getSectorCorners(*j, corners);
1785
1786                                 writeS16(buf, corners[0]);
1787                                 os.write((char*)buf, 2);
1788                                 writeS16(buf, corners[1]);
1789                                 os.write((char*)buf, 2);
1790                                 writeS16(buf, corners[2]);
1791                                 os.write((char*)buf, 2);
1792                                 writeS16(buf, corners[3]);
1793                                 os.write((char*)buf, 2);
1794                         }
1795
1796                         SharedBuffer<u8> data((u8*)os.str().c_str(), os.str().size());
1797
1798                         /*dstream<<"Server::SendSectorMeta(): sending packet"
1799                                         " with "<<sendlist.size()<<" sectors"<<std::endl;*/
1800
1801                         m_con.Send(peer_id, 1, data, true);
1802
1803                         if(i == ps.end())
1804                                 break;
1805
1806                         sendlist.clear();
1807                 }
1808
1809                 sendlist.push_back(*i);
1810                 i++;
1811         }
1812 }
1813 #endif
1814
1815 core::list<PlayerInfo> Server::getPlayerInfo()
1816 {
1817         DSTACK(__FUNCTION_NAME);
1818         JMutexAutoLock envlock(m_env_mutex);
1819         JMutexAutoLock conlock(m_con_mutex);
1820         
1821         core::list<PlayerInfo> list;
1822
1823         core::list<Player*> players = m_env.getPlayers();
1824         
1825         core::list<Player*>::Iterator i;
1826         for(i = players.begin();
1827                         i != players.end(); i++)
1828         {
1829                 PlayerInfo info;
1830
1831                 Player *player = *i;
1832                 try{
1833                         con::Peer *peer = m_con.GetPeer(player->peer_id);
1834                         info.id = peer->id;
1835                         info.address = peer->address;
1836                         info.avg_rtt = peer->avg_rtt;
1837                 }
1838                 catch(con::PeerNotFoundException &e)
1839                 {
1840                         // Outdated peer info
1841                         info.id = 0;
1842                         info.address = Address(0,0,0,0,0);
1843                         info.avg_rtt = 0.0;
1844                 }
1845
1846                 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
1847                 info.position = player->getPosition();
1848
1849                 list.push_back(info);
1850         }
1851
1852         return list;
1853 }
1854
1855 void Server::peerAdded(con::Peer *peer)
1856 {
1857         DSTACK(__FUNCTION_NAME);
1858         dout_server<<"Server::peerAdded(): peer->id="
1859                         <<peer->id<<std::endl;
1860         
1861         // Connection is already locked when this is called.
1862         //JMutexAutoLock lock(m_con_mutex);
1863         
1864         // Error check
1865         core::map<u16, RemoteClient*>::Node *n;
1866         n = m_clients.find(peer->id);
1867         // The client shouldn't already exist
1868         assert(n == NULL);
1869
1870         // Create client
1871         RemoteClient *client = new RemoteClient();
1872         client->peer_id = peer->id;
1873         m_clients.insert(client->peer_id, client);
1874
1875         // Create player
1876         {
1877                 // Already locked when called
1878                 //JMutexAutoLock envlock(m_env_mutex);
1879                 
1880                 Player *player = m_env.getPlayer(peer->id);
1881                 
1882                 // The player shouldn't already exist
1883                 assert(player == NULL);
1884
1885                 player = new RemotePlayer();
1886                 player->peer_id = peer->id;
1887
1888                 /*
1889                         Set player position
1890                 */
1891
1892                 // Get zero sector (it could have been unloaded to disk)
1893                 m_env.getMap().emergeSector(v2s16(0,0));
1894                 // Get ground height at origin
1895                 f32 groundheight = m_env.getMap().getGroundHeight(v2s16(0,0), true);
1896                 // The zero sector should have been generated
1897                 assert(groundheight > GROUNDHEIGHT_VALID_MINVALUE);
1898                 // Don't go underwater
1899                 if(groundheight < WATER_LEVEL)
1900                         groundheight = WATER_LEVEL;
1901
1902                 player->setPosition(intToFloat(v3s16(
1903                                 0,
1904                                 groundheight + 1,
1905                                 0
1906                 )));
1907
1908                 /*
1909                         Add player to environment
1910                 */
1911
1912                 m_env.addPlayer(player);
1913
1914                 /*
1915                         Add stuff to inventory
1916                 */
1917                 
1918                 if(m_creative_mode)
1919                 {
1920                         // Give all materials
1921                         assert(USEFUL_MATERIAL_COUNT <= PLAYER_INVENTORY_SIZE);
1922                         for(u16 i=0; i<USEFUL_MATERIAL_COUNT; i++)
1923                         {
1924                                 InventoryItem *item = new MaterialItem(i, 1);
1925                                 player->inventory.addItem(item);
1926                         }
1927                         // Sign
1928                         {
1929                                 InventoryItem *item = new MapBlockObjectItem("Sign Example text");
1930                                 bool r = player->inventory.addItem(item);
1931                                 assert(r == true);
1932                         }
1933                         // Rat
1934                         {
1935                                 InventoryItem *item = new MapBlockObjectItem("Rat");
1936                                 bool r = player->inventory.addItem(item);
1937                                 assert(r == true);
1938                         }
1939                 }
1940                 else
1941                 {
1942                         // Give some lights
1943                         {
1944                                 InventoryItem *item = new MaterialItem(3, 999);
1945                                 bool r = player->inventory.addItem(item);
1946                                 assert(r == true);
1947                         }
1948                         // and some signs
1949                         for(u16 i=0; i<4; i++)
1950                         {
1951                                 InventoryItem *item = new MapBlockObjectItem("Sign Example text");
1952                                 bool r = player->inventory.addItem(item);
1953                                 assert(r == true);
1954                         }
1955                         /*// and some rats
1956                         for(u16 i=0; i<4; i++)
1957                         {
1958                                 InventoryItem *item = new MapBlockObjectItem("Rat");
1959                                 bool r = player->inventory.addItem(item);
1960                                 assert(r == true);
1961                         }*/
1962                 }
1963         }
1964 }
1965
1966 void Server::deletingPeer(con::Peer *peer, bool timeout)
1967 {
1968         DSTACK(__FUNCTION_NAME);
1969         dout_server<<"Server::deletingPeer(): peer->id="
1970                         <<peer->id<<", timeout="<<timeout<<std::endl;
1971         
1972         // Connection is already locked when this is called.
1973         //JMutexAutoLock lock(m_con_mutex);
1974
1975         // Error check
1976         core::map<u16, RemoteClient*>::Node *n;
1977         n = m_clients.find(peer->id);
1978         // The client should exist
1979         assert(n != NULL);
1980         
1981         // Delete player
1982         {
1983                 // Already locked when called
1984                 //JMutexAutoLock envlock(m_env_mutex);
1985                 m_env.removePlayer(peer->id);
1986         }
1987         
1988         // Delete client
1989         delete m_clients[peer->id];
1990         m_clients.remove(peer->id);
1991
1992         // Send player info to all clients
1993         SendPlayerInfos();
1994 }
1995
1996 void Server::SendObjectData(float dtime)
1997 {
1998         DSTACK(__FUNCTION_NAME);
1999
2000         core::map<v3s16, bool> stepped_blocks;
2001         
2002         for(core::map<u16, RemoteClient*>::Iterator
2003                 i = m_clients.getIterator();
2004                 i.atEnd() == false; i++)
2005         {
2006                 u16 peer_id = i.getNode()->getKey();
2007                 RemoteClient *client = i.getNode()->getValue();
2008                 assert(client->peer_id == peer_id);
2009                 
2010                 if(client->serialization_version == SER_FMT_VER_INVALID)
2011                         continue;
2012                 
2013                 client->SendObjectData(this, dtime, stepped_blocks);
2014         }
2015 }
2016
2017 void Server::SendPlayerInfos()
2018 {
2019         DSTACK(__FUNCTION_NAME);
2020
2021         //JMutexAutoLock envlock(m_env_mutex);
2022         
2023         core::list<Player*> players = m_env.getPlayers();
2024         
2025         u32 player_count = players.getSize();
2026         u32 datasize = 2+(2+PLAYERNAME_SIZE)*player_count;
2027
2028         SharedBuffer<u8> data(datasize);
2029         writeU16(&data[0], TOCLIENT_PLAYERINFO);
2030         
2031         u32 start = 2;
2032         core::list<Player*>::Iterator i;
2033         for(i = players.begin();
2034                         i != players.end(); i++)
2035         {
2036                 Player *player = *i;
2037
2038                 /*dstream<<"Server sending player info for player with "
2039                                 "peer_id="<<player->peer_id<<std::endl;*/
2040                 
2041                 writeU16(&data[start], player->peer_id);
2042                 snprintf((char*)&data[start+2], PLAYERNAME_SIZE, "%s", player->getName());
2043                 start += 2+PLAYERNAME_SIZE;
2044         }
2045
2046         //JMutexAutoLock conlock(m_con_mutex);
2047
2048         // Send as reliable
2049         m_con.SendToAll(0, data, true);
2050 }
2051
2052 void Server::SendInventory(u16 peer_id)
2053 {
2054         DSTACK(__FUNCTION_NAME);
2055         
2056         //JMutexAutoLock envlock(m_env_mutex);
2057         
2058         Player* player = m_env.getPlayer(peer_id);
2059
2060         std::ostringstream os;
2061         //os.imbue(std::locale("C"));
2062
2063         player->inventory.serialize(os);
2064
2065         std::string s = os.str();
2066         
2067         SharedBuffer<u8> data(s.size()+2);
2068         writeU16(&data[0], TOCLIENT_INVENTORY);
2069         memcpy(&data[2], s.c_str(), s.size());
2070         
2071         //JMutexAutoLock conlock(m_con_mutex);
2072
2073         // Send as reliable
2074         m_con.Send(peer_id, 0, data, true);
2075 }
2076
2077 void Server::SendBlocks(float dtime)
2078 {
2079         DSTACK(__FUNCTION_NAME);
2080         //dstream<<"Server::SendBlocks(): BEGIN"<<std::endl;
2081
2082         JMutexAutoLock envlock(m_env_mutex);
2083         JMutexAutoLock conlock(m_con_mutex);
2084
2085         for(core::map<u16, RemoteClient*>::Iterator
2086                 i = m_clients.getIterator();
2087                 i.atEnd() == false; i++)
2088         {
2089                 RemoteClient *client = i.getNode()->getValue();
2090                 assert(client->peer_id == i.getNode()->getKey());
2091                 
2092                 if(client->serialization_version == SER_FMT_VER_INVALID)
2093                         continue;
2094
2095                 //dstream<<"Server::SendBlocks(): sending blocks for client "<<client->peer_id<<std::endl;
2096                 
2097                 //u16 peer_id = client->peer_id;
2098                 client->SendBlocks(this, dtime);
2099         }
2100
2101         //dstream<<"Server::SendBlocks(): END"<<std::endl;
2102 }
2103
2104 RemoteClient* Server::getClient(u16 peer_id)
2105 {
2106         DSTACK(__FUNCTION_NAME);
2107         //JMutexAutoLock lock(m_con_mutex);
2108         core::map<u16, RemoteClient*>::Node *n;
2109         n = m_clients.find(peer_id);
2110         // A client should exist for all peers
2111         assert(n != NULL);
2112         return n->getValue();
2113 }
2114
2115