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