]> git.lizzy.rs Git - dragonfireclient.git/blob - src/server.h
Reduced the CPU usage of the sent block selector algorithm
[dragonfireclient.git] / src / server.h
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 /*
21 (c) 2010 Perttu Ahola <celeron55@gmail.com>
22 */
23
24 #ifndef SERVER_HEADER
25 #define SERVER_HEADER
26
27 #include "connection.h"
28 #include "environment.h"
29 #include "common_irrlicht.h"
30 #include <string>
31 #include "utility.h"
32 #include "porting.h"
33 #include "map.h"
34 #include "inventory.h"
35 #include "auth.h"
36
37 /*
38         Some random functions
39 */
40 v3f findSpawnPos(ServerMap &map);
41
42 /*
43         A structure containing the data needed for queueing the fetching
44         of blocks.
45 */
46 struct QueuedBlockEmerge
47 {
48         v3s16 pos;
49         // key = peer_id, value = flags
50         core::map<u16, u8> peer_ids;
51 };
52
53 /*
54         This is a thread-safe class.
55 */
56 class BlockEmergeQueue
57 {
58 public:
59         BlockEmergeQueue()
60         {
61                 m_mutex.Init();
62         }
63
64         ~BlockEmergeQueue()
65         {
66                 JMutexAutoLock lock(m_mutex);
67
68                 core::list<QueuedBlockEmerge*>::Iterator i;
69                 for(i=m_queue.begin(); i!=m_queue.end(); i++)
70                 {
71                         QueuedBlockEmerge *q = *i;
72                         delete q;
73                 }
74         }
75         
76         /*
77                 peer_id=0 adds with nobody to send to
78         */
79         void addBlock(u16 peer_id, v3s16 pos, u8 flags)
80         {
81                 DSTACK(__FUNCTION_NAME);
82         
83                 JMutexAutoLock lock(m_mutex);
84
85                 if(peer_id != 0)
86                 {
87                         /*
88                                 Find if block is already in queue.
89                                 If it is, update the peer to it and quit.
90                         */
91                         core::list<QueuedBlockEmerge*>::Iterator i;
92                         for(i=m_queue.begin(); i!=m_queue.end(); i++)
93                         {
94                                 QueuedBlockEmerge *q = *i;
95                                 if(q->pos == pos)
96                                 {
97                                         q->peer_ids[peer_id] = flags;
98                                         return;
99                                 }
100                         }
101                 }
102                 
103                 /*
104                         Add the block
105                 */
106                 QueuedBlockEmerge *q = new QueuedBlockEmerge;
107                 q->pos = pos;
108                 if(peer_id != 0)
109                         q->peer_ids[peer_id] = flags;
110                 m_queue.push_back(q);
111         }
112
113         // Returned pointer must be deleted
114         // Returns NULL if queue is empty
115         QueuedBlockEmerge * pop()
116         {
117                 JMutexAutoLock lock(m_mutex);
118
119                 core::list<QueuedBlockEmerge*>::Iterator i = m_queue.begin();
120                 if(i == m_queue.end())
121                         return NULL;
122                 QueuedBlockEmerge *q = *i;
123                 m_queue.erase(i);
124                 return q;
125         }
126
127         u32 size()
128         {
129                 JMutexAutoLock lock(m_mutex);
130                 return m_queue.size();
131         }
132         
133         u32 peerItemCount(u16 peer_id)
134         {
135                 JMutexAutoLock lock(m_mutex);
136
137                 u32 count = 0;
138
139                 core::list<QueuedBlockEmerge*>::Iterator i;
140                 for(i=m_queue.begin(); i!=m_queue.end(); i++)
141                 {
142                         QueuedBlockEmerge *q = *i;
143                         if(q->peer_ids.find(peer_id) != NULL)
144                                 count++;
145                 }
146
147                 return count;
148         }
149
150 private:
151         core::list<QueuedBlockEmerge*> m_queue;
152         JMutex m_mutex;
153 };
154
155 class Server;
156
157 class ServerThread : public SimpleThread
158 {
159         Server *m_server;
160
161 public:
162
163         ServerThread(Server *server):
164                 SimpleThread(),
165                 m_server(server)
166         {
167         }
168
169         void * Thread();
170 };
171
172 class EmergeThread : public SimpleThread
173 {
174         Server *m_server;
175
176 public:
177
178         EmergeThread(Server *server):
179                 SimpleThread(),
180                 m_server(server)
181         {
182         }
183
184         void * Thread();
185
186         void trigger()
187         {
188                 setRun(true);
189                 if(IsRunning() == false)
190                 {
191                         Start();
192                 }
193         }
194 };
195
196 struct PlayerInfo
197 {
198         u16 id;
199         char name[PLAYERNAME_SIZE];
200         v3f position;
201         Address address;
202         float avg_rtt;
203
204         PlayerInfo();
205         void PrintLine(std::ostream *s);
206 };
207
208 u32 PIChecksum(core::list<PlayerInfo> &l);
209
210 /*
211         Used for queueing and sorting block transfers in containers
212         
213         Lower priority number means higher priority.
214 */
215 struct PrioritySortedBlockTransfer
216 {
217         PrioritySortedBlockTransfer(float a_priority, v3s16 a_pos, u16 a_peer_id)
218         {
219                 priority = a_priority;
220                 pos = a_pos;
221                 peer_id = a_peer_id;
222         }
223         bool operator < (PrioritySortedBlockTransfer &other)
224         {
225                 return priority < other.priority;
226         }
227         float priority;
228         v3s16 pos;
229         u16 peer_id;
230 };
231
232 class RemoteClient
233 {
234 public:
235         // peer_id=0 means this client has no associated peer
236         // NOTE: If client is made allowed to exist while peer doesn't,
237         //       this has to be set to 0 when there is no peer.
238         //       Also, the client must be moved to some other container.
239         u16 peer_id;
240         // The serialization version to use with the client
241         u8 serialization_version;
242         // Version is stored in here after INIT before INIT2
243         u8 pending_serialization_version;
244
245         RemoteClient():
246                 m_time_from_building(9999),
247                 m_excess_gotblocks(0)
248         {
249                 peer_id = 0;
250                 serialization_version = SER_FMT_VER_INVALID;
251                 pending_serialization_version = SER_FMT_VER_INVALID;
252                 m_nearest_unsent_d = 0;
253                 m_nearest_unsent_reset_timer = 0.0;
254                 m_nothing_to_send_counter = 0;
255                 m_nothing_to_send_pause_timer = 0;
256         }
257         ~RemoteClient()
258         {
259         }
260         
261         /*
262                 Finds block that should be sent next to the client.
263                 Environment should be locked when this is called.
264                 dtime is used for resetting send radius at slow interval
265         */
266         void GetNextBlocks(Server *server, float dtime,
267                         core::array<PrioritySortedBlockTransfer> &dest);
268
269         /*
270                 Connection and environment should be locked when this is called.
271                 steps() objects of blocks not found in active_blocks, then
272                 adds those blocks to active_blocks
273         */
274         void SendObjectData(
275                         Server *server,
276                         float dtime,
277                         core::map<v3s16, bool> &stepped_blocks
278                 );
279
280         void GotBlock(v3s16 p);
281
282         void SentBlock(v3s16 p);
283
284         void SetBlockNotSent(v3s16 p);
285         void SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks);
286
287         s32 SendingCount()
288         {
289                 return m_blocks_sending.size();
290         }
291         
292         // Increments timeouts and removes timed-out blocks from list
293         // NOTE: This doesn't fix the server-not-sending-block bug
294         //       because it is related to emerging, not sending.
295         //void RunSendingTimeouts(float dtime, float timeout);
296
297         void PrintInfo(std::ostream &o)
298         {
299                 o<<"RemoteClient "<<peer_id<<": "
300                                 <<"m_blocks_sent.size()="<<m_blocks_sent.size()
301                                 <<", m_blocks_sending.size()="<<m_blocks_sending.size()
302                                 <<", m_nearest_unsent_d="<<m_nearest_unsent_d
303                                 <<", m_excess_gotblocks="<<m_excess_gotblocks
304                                 <<std::endl;
305                 m_excess_gotblocks = 0;
306         }
307
308         // Time from last placing or removing blocks
309         float m_time_from_building;
310         
311         /*JMutex m_dig_mutex;
312         float m_dig_time_remaining;
313         // -1 = not digging
314         s16 m_dig_tool_item;
315         v3s16 m_dig_position;*/
316         
317         /*
318                 List of active objects that the client knows of.
319                 Value is dummy.
320         */
321         core::map<u16, bool> m_known_objects;
322
323 private:
324         /*
325                 Blocks that have been sent to client.
326                 - These don't have to be sent again.
327                 - A block is cleared from here when client says it has
328                   deleted it from it's memory
329                 
330                 Key is position, value is dummy.
331                 No MapBlock* is stored here because the blocks can get deleted.
332         */
333         core::map<v3s16, bool> m_blocks_sent;
334         s16 m_nearest_unsent_d;
335         v3s16 m_last_center;
336         float m_nearest_unsent_reset_timer;
337         
338         /*
339                 Blocks that are currently on the line.
340                 This is used for throttling the sending of blocks.
341                 - The size of this list is limited to some value
342                 Block is added when it is sent with BLOCKDATA.
343                 Block is removed when GOTBLOCKS is received.
344                 Value is time from sending. (not used at the moment)
345         */
346         core::map<v3s16, float> m_blocks_sending;
347
348         /*
349                 Count of excess GotBlocks().
350                 There is an excess amount because the client sometimes
351                 gets a block so late that the server sends it again,
352                 and the client then sends two GOTBLOCKs.
353                 This is resetted by PrintInfo()
354         */
355         u32 m_excess_gotblocks;
356         
357         // CPU usage optimization
358         u32 m_nothing_to_send_counter;
359         float m_nothing_to_send_pause_timer;
360 };
361
362 class Server : public con::PeerHandler, public MapEventReceiver,
363                 public InventoryManager
364 {
365 public:
366         /*
367                 NOTE: Every public method should be thread-safe
368         */
369
370         Server(
371                 std::string mapsavedir
372         );
373         ~Server();
374         void start(unsigned short port);
375         void stop();
376         // This is mainly a way to pass the time to the server.
377         // Actual processing is done in an another thread.
378         void step(float dtime);
379         // This is run by ServerThread and does the actual processing
380         void AsyncRunStep();
381         void Receive();
382         void ProcessData(u8 *data, u32 datasize, u16 peer_id);
383
384         core::list<PlayerInfo> getPlayerInfo();
385
386         /*u32 getDayNightRatio()
387         {
388                 return time_to_daynight_ratio(m_time_of_day.get());
389         }*/
390         
391         // Environment must be locked when called
392         void setTimeOfDay(u32 time)
393         {
394                 m_env.setTimeOfDay(time);
395                 m_time_of_day_send_timer = 0;
396         }
397
398         bool getShutdownRequested()
399         {
400                 return m_shutdown_requested;
401         }
402         
403         /*
404                 Shall be called with the environment locked.
405                 This is accessed by the map, which is inside the environment,
406                 so it shouldn't be a problem.
407         */
408         void onMapEditEvent(MapEditEvent *event);
409
410         /*
411                 Shall be called with the environment and the connection locked.
412         */
413         Inventory* getInventory(InventoryContext *c, std::string id);
414         void inventoryModified(InventoryContext *c, std::string id);
415
416         // Connection must be locked when called
417         std::wstring getStatusString();
418
419         void requestShutdown(void)
420         {
421                 m_shutdown_requested = true;
422         }
423
424
425         // Envlock and conlock should be locked when calling this
426         void SendMovePlayer(Player *player);
427         
428         u64 getPlayerAuthPrivs(const std::string &name)
429         {
430                 try{
431                         return m_authmanager.getPrivs(name);
432                 }
433                 catch(AuthNotFoundException &e)
434                 {
435                         dstream<<"WARNING: Auth not found for "<<name<<std::endl;
436                         return 0;
437                 }
438         }
439
440         void setPlayerAuthPrivs(const std::string &name, u64 privs)
441         {
442                 try{
443                         return m_authmanager.setPrivs(name, privs);
444                 }
445                 catch(AuthNotFoundException &e)
446                 {
447                         dstream<<"WARNING: Auth not found for "<<name<<std::endl;
448                 }
449         }
450
451 private:
452
453         // con::PeerHandler implementation.
454         // These queue stuff to be processed by handlePeerChanges().
455         // As of now, these create and remove clients and players.
456         void peerAdded(con::Peer *peer);
457         void deletingPeer(con::Peer *peer, bool timeout);
458         
459         /*
460                 Static send methods
461         */
462         
463         static void SendHP(con::Connection &con, u16 peer_id, u8 hp);
464         static void SendAccessDenied(con::Connection &con, u16 peer_id,
465                         const std::wstring &reason);
466         
467         /*
468                 Non-static send methods
469         */
470
471         // Envlock and conlock should be locked when calling these
472         void SendObjectData(float dtime);
473         void SendPlayerInfos();
474         void SendInventory(u16 peer_id);
475         void SendChatMessage(u16 peer_id, const std::wstring &message);
476         void BroadcastChatMessage(const std::wstring &message);
477         void SendPlayerHP(Player *player);
478         /*
479                 Send a node removal/addition event to all clients except ignore_id.
480                 Additionally, if far_players!=NULL, players further away than
481                 far_d_nodes are ignored and their peer_ids are added to far_players
482         */
483         void sendRemoveNode(v3s16 p, u16 ignore_id=0,
484                         core::list<u16> *far_players=NULL, float far_d_nodes=100);
485         void sendAddNode(v3s16 p, MapNode n, u16 ignore_id=0,
486                         core::list<u16> *far_players=NULL, float far_d_nodes=100);
487         
488         // Environment and Connection must be locked when called
489         void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver);
490         
491         // Sends blocks to clients
492         void SendBlocks(float dtime);
493
494         /*
495                 Something random
496         */
497         
498         void UpdateCrafting(u16 peer_id);
499         
500         // When called, connection mutex should be locked
501         RemoteClient* getClient(u16 peer_id);
502         
503         // When called, environment mutex should be locked
504         std::string getPlayerName(u16 peer_id)
505         {
506                 Player *player = m_env.getPlayer(peer_id);
507                 if(player == NULL)
508                         return "[id="+itos(peer_id);
509                 return player->getName();
510         }
511
512         /*
513                 Get a player from memory or creates one.
514                 If player is already connected, return NULL
515                 The password is not checked here - it is only used to
516                 set the password if a new player is created.
517
518                 Call with env and con locked.
519         */
520         Player *emergePlayer(const char *name, const char *password, u16 peer_id);
521         
522         // Locks environment and connection by its own
523         struct PeerChange;
524         void handlePeerChange(PeerChange &c);
525         void handlePeerChanges();
526
527         u64 getPlayerPrivs(Player *player);
528
529         /*
530                 Variables
531         */
532         
533         // Some timers
534         float m_liquid_transform_timer;
535         float m_print_info_timer;
536         float m_objectdata_timer;
537         float m_emergethread_trigger_timer;
538         float m_savemap_timer;
539         
540         // NOTE: If connection and environment are both to be locked,
541         // environment shall be locked first.
542
543         // Environment
544         ServerEnvironment m_env;
545         JMutex m_env_mutex;
546         
547         // Connection
548         con::Connection m_con;
549         JMutex m_con_mutex;
550         // Connected clients (behind the con mutex)
551         core::map<u16, RemoteClient*> m_clients;
552
553         // User authentication
554         AuthManager m_authmanager;
555         
556         /*
557                 Threads
558         */
559         
560         // A buffer for time steps
561         // step() increments and AsyncRunStep() run by m_thread reads it.
562         float m_step_dtime;
563         JMutex m_step_dtime_mutex;
564
565         // The server mainly operates in this thread
566         ServerThread m_thread;
567         // This thread fetches and generates map
568         EmergeThread m_emergethread;
569         // Queue of block coordinates to be processed by the emerge thread
570         BlockEmergeQueue m_emerge_queue;
571         
572         /*
573                 Time related stuff
574         */
575
576         // 0-23999
577         //MutexedVariable<u32> m_time_of_day;
578         // Used to buffer dtime for adding to m_time_of_day
579         float m_time_counter;
580         // Timer for sending time of day over network
581         float m_time_of_day_send_timer;
582         // Uptime of server in seconds
583         MutexedVariable<double> m_uptime;
584         
585         /*
586                 Peer change queue.
587                 Queues stuff from peerAdded() and deletingPeer() to
588                 handlePeerChanges()
589         */
590         enum PeerChangeType
591         {
592                 PEER_ADDED,
593                 PEER_REMOVED
594         };
595         struct PeerChange
596         {
597                 PeerChangeType type;
598                 u16 peer_id;
599                 bool timeout;
600         };
601         Queue<PeerChange> m_peer_change_queue;
602
603         /*
604                 Random stuff
605         */
606
607         // Map directory
608         std::string m_mapsavedir;
609
610         bool m_shutdown_requested;
611         
612         /*
613                 Map edit event queue. Automatically receives all map edits.
614                 The constructor of this class registers us to receive them through
615                 onMapEditEvent
616
617                 NOTE: Should these be moved to actually be members of
618                 ServerEnvironment?
619         */
620
621         /*
622                 Queue of map edits from the environment for sending to the clients
623                 This is behind m_env_mutex
624         */
625         Queue<MapEditEvent*> m_unsent_map_edit_queue;
626         /*
627                 Set to true when the server itself is modifying the map and does
628                 all sending of information by itself.
629                 This is behind m_env_mutex
630         */
631         bool m_ignore_map_edit_events;
632         /*
633                 If set to !=0, the incoming MapEditEvents are modified to have
634                 this peed id as the disabled recipient
635                 This is behind m_env_mutex
636         */
637         u16 m_ignore_map_edit_events_peer_id;
638
639         Profiler *m_profiler;
640
641         friend class EmergeThread;
642         friend class RemoteClient;
643 };
644
645 /*
646         Runs a simple dedicated server loop.
647
648         Shuts down when run is set to false.
649 */
650 void dedicated_server_loop(Server &server, bool &run);
651
652 #endif
653