Ctrl+C handling on POSIX, some commands for server and other tweaking
[oweals/minetest.git] / src / server.h
1 /*
2 Minetest-c55
3 Copyright (C) 2010 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
34 struct QueuedBlockEmerge
35 {
36         v3s16 pos;
37         // key = peer_id, value = flags
38         core::map<u16, u8> peer_ids;
39 };
40
41 /*
42         This is a thread-safe class.
43 */
44 class BlockEmergeQueue
45 {
46 public:
47         BlockEmergeQueue()
48         {
49                 m_mutex.Init();
50         }
51
52         ~BlockEmergeQueue()
53         {
54                 JMutexAutoLock lock(m_mutex);
55
56                 core::list<QueuedBlockEmerge*>::Iterator i;
57                 for(i=m_queue.begin(); i!=m_queue.end(); i++)
58                 {
59                         QueuedBlockEmerge *q = *i;
60                         delete q;
61                 }
62         }
63         
64         /*
65                 peer_id=0 adds with nobody to send to
66         */
67         void addBlock(u16 peer_id, v3s16 pos, u8 flags)
68         {
69                 DSTACK(__FUNCTION_NAME);
70         
71                 JMutexAutoLock lock(m_mutex);
72
73                 if(peer_id != 0)
74                 {
75                         /*
76                                 Find if block is already in queue.
77                                 If it is, update the peer to it and quit.
78                         */
79                         core::list<QueuedBlockEmerge*>::Iterator i;
80                         for(i=m_queue.begin(); i!=m_queue.end(); i++)
81                         {
82                                 QueuedBlockEmerge *q = *i;
83                                 if(q->pos == pos)
84                                 {
85                                         q->peer_ids[peer_id] = flags;
86                                         return;
87                                 }
88                         }
89                 }
90                 
91                 /*
92                         Add the block
93                 */
94                 QueuedBlockEmerge *q = new QueuedBlockEmerge;
95                 q->pos = pos;
96                 if(peer_id != 0)
97                         q->peer_ids[peer_id] = flags;
98                 m_queue.push_back(q);
99         }
100
101         // Returned pointer must be deleted
102         // Returns NULL if queue is empty
103         QueuedBlockEmerge * pop()
104         {
105                 JMutexAutoLock lock(m_mutex);
106
107                 core::list<QueuedBlockEmerge*>::Iterator i = m_queue.begin();
108                 if(i == m_queue.end())
109                         return NULL;
110                 QueuedBlockEmerge *q = *i;
111                 m_queue.erase(i);
112                 return q;
113         }
114
115         u32 size()
116         {
117                 JMutexAutoLock lock(m_mutex);
118                 return m_queue.size();
119         }
120         
121         u32 peerItemCount(u16 peer_id)
122         {
123                 JMutexAutoLock lock(m_mutex);
124
125                 u32 count = 0;
126
127                 core::list<QueuedBlockEmerge*>::Iterator i;
128                 for(i=m_queue.begin(); i!=m_queue.end(); i++)
129                 {
130                         QueuedBlockEmerge *q = *i;
131                         if(q->peer_ids.find(peer_id) != NULL)
132                                 count++;
133                 }
134
135                 return count;
136         }
137
138 private:
139         core::list<QueuedBlockEmerge*> m_queue;
140         JMutex m_mutex;
141 };
142
143 class Server;
144
145 class ServerThread : public SimpleThread
146 {
147         Server *m_server;
148
149 public:
150
151         ServerThread(Server *server):
152                 SimpleThread(),
153                 m_server(server)
154         {
155         }
156
157         void * Thread();
158 };
159
160 class EmergeThread : public SimpleThread
161 {
162         Server *m_server;
163
164 public:
165
166         EmergeThread(Server *server):
167                 SimpleThread(),
168                 m_server(server)
169         {
170         }
171
172         void * Thread();
173
174         void trigger()
175         {
176                 setRun(true);
177                 if(IsRunning() == false)
178                 {
179                         Start();
180                 }
181         }
182 };
183
184 struct PlayerInfo
185 {
186         u16 id;
187         char name[PLAYERNAME_SIZE];
188         v3f position;
189         Address address;
190         float avg_rtt;
191
192         PlayerInfo();
193         void PrintLine(std::ostream *s);
194 };
195
196 u32 PIChecksum(core::list<PlayerInfo> &l);
197
198 /*
199         Used for queueing and sorting block transfers in containers
200         
201         Lower priority number means higher priority.
202 */
203 struct PrioritySortedBlockTransfer
204 {
205         PrioritySortedBlockTransfer(float a_priority, v3s16 a_pos, u16 a_peer_id)
206         {
207                 priority = a_priority;
208                 pos = a_pos;
209                 peer_id = a_peer_id;
210         }
211         bool operator < (PrioritySortedBlockTransfer &other)
212         {
213                 return priority < other.priority;
214         }
215         float priority;
216         v3s16 pos;
217         u16 peer_id;
218 };
219
220 class RemoteClient
221 {
222 public:
223         // peer_id=0 means this client has no associated peer
224         // NOTE: If client is made allowed to exist while peer doesn't,
225         //       this has to be set to 0 when there is no peer.
226         //       Also, the client must be moved to some other container.
227         u16 peer_id;
228         // The serialization version to use with the client
229         u8 serialization_version;
230         // Version is stored in here after INIT before INIT2
231         u8 pending_serialization_version;
232
233         RemoteClient():
234                 m_time_from_building(9999),
235                 m_excess_gotblocks(0)
236         {
237                 peer_id = 0;
238                 serialization_version = SER_FMT_VER_INVALID;
239                 pending_serialization_version = SER_FMT_VER_INVALID;
240                 m_nearest_unsent_d = 0;
241                 m_nearest_unsent_reset_timer = 0.0;
242
243                 m_blocks_sent_mutex.Init();
244                 m_blocks_sending_mutex.Init();
245                 
246                 /*m_dig_mutex.Init();
247                 m_dig_time_remaining = 0;
248                 m_dig_tool_item = -1;*/
249         }
250         ~RemoteClient()
251         {
252         }
253         
254         /*
255                 Finds block that should be sent next to the client.
256                 Environment should be locked when this is called.
257                 dtime is used for resetting send radius at slow interval
258         */
259         void GetNextBlocks(Server *server, float dtime,
260                         core::array<PrioritySortedBlockTransfer> &dest);
261
262         /*
263                 Connection and environment should be locked when this is called.
264                 steps() objects of blocks not found in active_blocks, then
265                 adds those blocks to active_blocks
266         */
267         void SendObjectData(
268                         Server *server,
269                         float dtime,
270                         core::map<v3s16, bool> &stepped_blocks
271                 );
272
273         void GotBlock(v3s16 p);
274
275         void SentBlock(v3s16 p);
276
277         void SetBlockNotSent(v3s16 p);
278         void SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks);
279
280         s32 SendingCount()
281         {
282                 JMutexAutoLock lock(m_blocks_sending_mutex);
283                 return m_blocks_sending.size();
284         }
285         
286         // Increments timeouts and removes timed-out blocks from list
287         // NOTE: This doesn't fix the server-not-sending-block bug
288         //       because it is related to emerging, not sending.
289         //void RunSendingTimeouts(float dtime, float timeout);
290
291         void PrintInfo(std::ostream &o)
292         {
293                 JMutexAutoLock l2(m_blocks_sent_mutex);
294                 JMutexAutoLock l3(m_blocks_sending_mutex);
295                 o<<"RemoteClient "<<peer_id<<": "
296                                 <<", m_blocks_sent.size()="<<m_blocks_sent.size()
297                                 <<", m_blocks_sending.size()="<<m_blocks_sending.size()
298                                 <<", m_nearest_unsent_d="<<m_nearest_unsent_d
299                                 <<", m_excess_gotblocks="<<m_excess_gotblocks
300                                 <<std::endl;
301                 m_excess_gotblocks = 0;
302         }
303
304         // Time from last placing or removing blocks
305         MutexedVariable<float> m_time_from_building;
306         
307         /*JMutex m_dig_mutex;
308         float m_dig_time_remaining;
309         // -1 = not digging
310         s16 m_dig_tool_item;
311         v3s16 m_dig_position;*/
312
313 private:
314         /*
315                 All members that are accessed by many threads should
316                 obviously be behind a mutex. The threads include:
317                 - main thread (calls step())
318                 - server thread (calls AsyncRunStep() and Receive())
319                 - emerge thread 
320         */
321         
322         //TODO: core::map<v3s16, MapBlock*> m_active_blocks
323         //NOTE: Not here, it should be server-wide!
324
325         // Number of blocks in the emerge queue that have this client as
326         // a receiver. Used for throttling network usage.
327         //MutexedVariable<s16> m_num_blocks_in_emerge_queue;
328
329         /*
330                 Blocks that have been sent to client.
331                 - These don't have to be sent again.
332                 - A block is cleared from here when client says it has
333                   deleted it from it's memory
334                 
335                 Key is position, value is dummy.
336                 No MapBlock* is stored here because the blocks can get deleted.
337         */
338         core::map<v3s16, bool> m_blocks_sent;
339         s16 m_nearest_unsent_d;
340         v3s16 m_last_center;
341         float m_nearest_unsent_reset_timer;
342         JMutex m_blocks_sent_mutex;
343         /*
344                 Blocks that are currently on the line.
345                 This is used for throttling the sending of blocks.
346                 - The size of this list is limited to some value
347                 Block is added when it is sent with BLOCKDATA.
348                 Block is removed when GOTBLOCKS is received.
349                 Value is time from sending. (not used at the moment)
350         */
351         core::map<v3s16, float> m_blocks_sending;
352         JMutex m_blocks_sending_mutex;
353
354         /*
355                 Count of excess GotBlocks().
356                 There is an excess amount because the client sometimes
357                 gets a block so late that the server sends it again,
358                 and the client then sends two GOTBLOCKs.
359                 This is resetted by PrintInfo()
360         */
361         u32 m_excess_gotblocks;
362 };
363
364 /*struct ServerSettings
365 {
366         ServerSettings()
367         {
368                 creative_mode = false;
369         }
370         bool creative_mode;
371 };*/
372
373 class Server : public con::PeerHandler
374 {
375 public:
376         /*
377                 NOTE: Every public method should be thread-safe
378         */
379         Server(
380                 std::string mapsavedir
381         );
382         ~Server();
383         void start(unsigned short port);
384         void stop();
385         // This is mainly a way to pass the time to the server.
386         // Actual processing is done in an another thread.
387         void step(float dtime);
388         // This is run by ServerThread and does the actual processing
389         void AsyncRunStep();
390         void Receive();
391         void ProcessData(u8 *data, u32 datasize, u16 peer_id);
392
393         // Environment and Connection must be locked when  called
394         void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver);
395         
396         //
397         
398         core::list<PlayerInfo> getPlayerInfo();
399
400         u32 getDayNightRatio()
401         {
402                 s32 d = 8;
403                 s32 t = (((m_time_of_day.get() + 24000/d/2)%24000)/(24000/d));
404                 if(t == d/4 || t == (d-d/4))
405                         return 600;
406                 else if(t < d/4 || t > (d-d/4))
407                         return 300;
408                 else
409                         return 1000;
410         }
411
412         bool getShutdownRequested()
413         {
414                 return m_shutdown_requested.get();
415         }
416
417 private:
418
419         // Virtual methods from con::PeerHandler.
420         // As of now, these create and remove clients and players.
421         void peerAdded(con::Peer *peer);
422         void deletingPeer(con::Peer *peer, bool timeout);
423         
424         // Envlock and conlock should be locked when calling these
425         void SendObjectData(float dtime);
426         void SendPlayerInfos();
427         void SendInventory(u16 peer_id);
428         void SendChatMessage(u16 peer_id, const std::wstring &message);
429         void BroadcastChatMessage(const std::wstring &message);
430         
431         // Sends blocks to clients
432         void SendBlocks(float dtime);
433         
434         // When called, connection mutex should be locked
435         RemoteClient* getClient(u16 peer_id);
436         
437         // Connection must be locked when called
438         std::wstring getStatusString();
439         
440         /*
441                 Get a player from memory or creates one.
442                 If player is already connected, return NULL
443
444                 Call with env and con locked.
445         */
446         Player *emergePlayer(const char *name, const char *password,
447                         u16 peer_id);
448
449         /*
450                 Update water pressure.
451                 This also adds suitable nodes to active_nodes.
452
453                 environment has to be locked when calling.
454         */
455         /*void UpdateBlockWaterPressure(MapBlock *block,
456                         core::map<v3s16, MapBlock*> &modified_blocks);*/
457         
458         // Locks environment and connection by its own
459         struct PeerChange;
460         void handlePeerChange(PeerChange &c);
461         void handlePeerChanges();
462         
463         //float m_flowwater_timer;
464         float m_liquid_transform_timer;
465         float m_print_info_timer;
466         float m_objectdata_timer;
467         float m_emergethread_trigger_timer;
468         float m_savemap_timer;
469         
470         // NOTE: If connection and environment are both to be locked,
471         // environment shall be locked first.
472         JMutex m_env_mutex;
473         Environment m_env;
474
475         JMutex m_con_mutex;
476         con::Connection m_con;
477         core::map<u16, RemoteClient*> m_clients; // Behind the con mutex
478
479         float m_step_dtime;
480         JMutex m_step_dtime_mutex;
481
482         ServerThread m_thread;
483         EmergeThread m_emergethread;
484
485         BlockEmergeQueue m_emerge_queue;
486         
487         // Nodes that are destinations of flowing liquid at the moment
488         //core::map<v3s16, u8> m_flow_active_nodes;
489
490         // 0-23999
491         MutexedVariable<u32> m_time_of_day;
492         // Used to buffer dtime for adding to m_time_of_day
493         float m_time_counter;
494         float m_time_of_day_send_timer;
495         
496         MutexedVariable<double> m_uptime;
497         
498         enum PeerChangeType
499         {
500                 PEER_ADDED,
501                 PEER_REMOVED
502         };
503
504         struct PeerChange
505         {
506                 PeerChangeType type;
507                 u16 peer_id;
508                 bool timeout;
509         };
510         
511         Queue<PeerChange> m_peer_change_queue;
512
513         std::string m_mapsavedir;
514
515         MutexedVariable<bool> m_shutdown_requested;
516
517         friend class EmergeThread;
518         friend class RemoteClient;
519 };
520
521 /*
522         Runs a simple dedicated server loop.
523
524         Shuts down when run is set to false.
525 */
526 void dedicated_server_loop(Server &server, bool &run);
527
528 #endif
529