]> git.lizzy.rs Git - dragonfireclient.git/blob - src/server.h
Fixed insufficient error handling in narrow_to_wide, which caused a crash if the...
[dragonfireclient.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         ~RemoteClient()
244         {
245         }
246         
247         /*
248                 Finds block that should be sent next to the client.
249                 Environment should be locked when this is called.
250                 dtime is used for resetting send radius at slow interval
251         */
252         void GetNextBlocks(Server *server, float dtime,
253                         core::array<PrioritySortedBlockTransfer> &dest);
254
255         /*
256                 Connection and environment should be locked when this is called.
257                 steps() objects of blocks not found in active_blocks, then
258                 adds those blocks to active_blocks
259         */
260         void SendObjectData(
261                         Server *server,
262                         float dtime,
263                         core::map<v3s16, bool> &stepped_blocks
264                 );
265
266         void GotBlock(v3s16 p);
267
268         void SentBlock(v3s16 p);
269
270         void SetBlockNotSent(v3s16 p);
271         void SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks);
272
273         s32 SendingCount()
274         {
275                 return m_blocks_sending.size();
276         }
277         
278         // Increments timeouts and removes timed-out blocks from list
279         // NOTE: This doesn't fix the server-not-sending-block bug
280         //       because it is related to emerging, not sending.
281         //void RunSendingTimeouts(float dtime, float timeout);
282
283         void PrintInfo(std::ostream &o)
284         {
285                 o<<"RemoteClient "<<peer_id<<": "
286                                 <<", m_blocks_sent.size()="<<m_blocks_sent.size()
287                                 <<", m_blocks_sending.size()="<<m_blocks_sending.size()
288                                 <<", m_nearest_unsent_d="<<m_nearest_unsent_d
289                                 <<", m_excess_gotblocks="<<m_excess_gotblocks
290                                 <<std::endl;
291                 m_excess_gotblocks = 0;
292         }
293
294         // Time from last placing or removing blocks
295         float m_time_from_building;
296         
297         /*JMutex m_dig_mutex;
298         float m_dig_time_remaining;
299         // -1 = not digging
300         s16 m_dig_tool_item;
301         v3s16 m_dig_position;*/
302         
303         /*
304                 List of active objects that the client knows of.
305                 Value is dummy.
306         */
307         core::map<u16, bool> m_known_objects;
308
309 private:
310         /*
311                 Blocks that have been sent to client.
312                 - These don't have to be sent again.
313                 - A block is cleared from here when client says it has
314                   deleted it from it's memory
315                 
316                 Key is position, value is dummy.
317                 No MapBlock* is stored here because the blocks can get deleted.
318         */
319         core::map<v3s16, bool> m_blocks_sent;
320         s16 m_nearest_unsent_d;
321         v3s16 m_last_center;
322         float m_nearest_unsent_reset_timer;
323         
324         /*
325                 Blocks that are currently on the line.
326                 This is used for throttling the sending of blocks.
327                 - The size of this list is limited to some value
328                 Block is added when it is sent with BLOCKDATA.
329                 Block is removed when GOTBLOCKS is received.
330                 Value is time from sending. (not used at the moment)
331         */
332         core::map<v3s16, float> m_blocks_sending;
333
334         /*
335                 Count of excess GotBlocks().
336                 There is an excess amount because the client sometimes
337                 gets a block so late that the server sends it again,
338                 and the client then sends two GOTBLOCKs.
339                 This is resetted by PrintInfo()
340         */
341         u32 m_excess_gotblocks;
342 };
343
344 class Server : public con::PeerHandler
345 {
346 public:
347         /*
348                 NOTE: Every public method should be thread-safe
349         */
350         Server(
351                 std::string mapsavedir
352         );
353         ~Server();
354         void start(unsigned short port);
355         void stop();
356         // This is mainly a way to pass the time to the server.
357         // Actual processing is done in an another thread.
358         void step(float dtime);
359         // This is run by ServerThread and does the actual processing
360         void AsyncRunStep();
361         void Receive();
362         void ProcessData(u8 *data, u32 datasize, u16 peer_id);
363
364         // Environment and Connection must be locked when  called
365         void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver);
366         
367         //
368         
369         core::list<PlayerInfo> getPlayerInfo();
370
371         u32 getDayNightRatio()
372         {
373                 s32 d = 8;
374                 s32 t = (((m_time_of_day.get() + 24000/d/2)%24000)/(24000/d));
375                 if(t == d/4 || t == (d-d/4))
376                         return 600;
377                 else if(t < d/4 || t > (d-d/4))
378                         return 300;
379                 else
380                         return 1000;
381         }
382
383         bool getShutdownRequested()
384         {
385                 return m_shutdown_requested.get();
386         }
387
388 private:
389
390         // Virtual methods from con::PeerHandler.
391         // As of now, these create and remove clients and players.
392         void peerAdded(con::Peer *peer);
393         void deletingPeer(con::Peer *peer, bool timeout);
394         
395         // Envlock and conlock should be locked when calling these
396         void SendObjectData(float dtime);
397         void SendPlayerInfos();
398         void SendInventory(u16 peer_id);
399         void SendChatMessage(u16 peer_id, const std::wstring &message);
400         void BroadcastChatMessage(const std::wstring &message);
401         
402         // Sends blocks to clients
403         void SendBlocks(float dtime);
404         
405         // When called, connection mutex should be locked
406         RemoteClient* getClient(u16 peer_id);
407         
408         // Connection must be locked when called
409         std::wstring getStatusString();
410         
411         /*
412                 Get a player from memory or creates one.
413                 If player is already connected, return NULL
414
415                 Call with env and con locked.
416         */
417         Player *emergePlayer(const char *name, const char *password,
418                         u16 peer_id);
419
420         /*
421                 Update water pressure.
422                 This also adds suitable nodes to active_nodes.
423
424                 environment has to be locked when calling.
425         */
426         /*void UpdateBlockWaterPressure(MapBlock *block,
427                         core::map<v3s16, MapBlock*> &modified_blocks);*/
428         
429         // Locks environment and connection by its own
430         struct PeerChange;
431         void handlePeerChange(PeerChange &c);
432         void handlePeerChanges();
433         
434         //float m_flowwater_timer;
435         float m_liquid_transform_timer;
436         float m_print_info_timer;
437         float m_objectdata_timer;
438         float m_emergethread_trigger_timer;
439         float m_savemap_timer;
440         
441         // NOTE: If connection and environment are both to be locked,
442         // environment shall be locked first.
443         JMutex m_env_mutex;
444         ServerEnvironment m_env;
445
446         JMutex m_con_mutex;
447         con::Connection m_con;
448         core::map<u16, RemoteClient*> m_clients; // Behind the con mutex
449
450         float m_step_dtime;
451         JMutex m_step_dtime_mutex;
452
453         ServerThread m_thread;
454         EmergeThread m_emergethread;
455
456         BlockEmergeQueue m_emerge_queue;
457         
458         // Nodes that are destinations of flowing liquid at the moment
459         //core::map<v3s16, u8> m_flow_active_nodes;
460
461         // 0-23999
462         MutexedVariable<u32> m_time_of_day;
463         // Used to buffer dtime for adding to m_time_of_day
464         float m_time_counter;
465         float m_time_of_day_send_timer;
466         
467         MutexedVariable<double> m_uptime;
468         
469         enum PeerChangeType
470         {
471                 PEER_ADDED,
472                 PEER_REMOVED
473         };
474
475         struct PeerChange
476         {
477                 PeerChangeType type;
478                 u16 peer_id;
479                 bool timeout;
480         };
481         
482         Queue<PeerChange> m_peer_change_queue;
483
484         std::string m_mapsavedir;
485
486         MutexedVariable<bool> m_shutdown_requested;
487
488         friend class EmergeThread;
489         friend class RemoteClient;
490 };
491
492 /*
493         Runs a simple dedicated server loop.
494
495         Shuts down when run is set to false.
496 */
497 void dedicated_server_loop(Server &server, bool &run);
498
499 #endif
500