Tune caves
[oweals/minetest.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 #ifndef SERVER_HEADER
21 #define SERVER_HEADER
22
23 #include "connection.h"
24 #include "environment.h"
25 #include "common_irrlicht.h"
26 #include <string>
27 #include "porting.h"
28 #include "map.h"
29 #include "inventory.h"
30 #include "auth.h"
31 #include "ban.h"
32 #include "gamedef.h"
33 #include "serialization.h" // For SER_FMT_VER_INVALID
34 #include "serverremoteplayer.h"
35 #include "mods.h"
36 #include "inventorymanager.h"
37 #include "subgame.h"
38 #include "sound.h"
39 struct LuaState;
40 typedef struct lua_State lua_State;
41 class IWritableItemDefManager;
42 class IWritableNodeDefManager;
43 class IWritableCraftDefManager;
44 class EventManager;
45
46 class ServerError : public std::exception
47 {
48 public:
49         ServerError(const std::string &s)
50         {
51                 m_s = "ServerError: ";
52                 m_s += s;
53         }
54         virtual ~ServerError() throw()
55         {}
56         virtual const char * what() const throw()
57         {
58                 return m_s.c_str();
59         }
60         std::string m_s;
61 };
62
63 /*
64         Some random functions
65 */
66 v3f findSpawnPos(ServerMap &map);
67
68 /*
69         A structure containing the data needed for queueing the fetching
70         of blocks.
71 */
72 struct QueuedBlockEmerge
73 {
74         v3s16 pos;
75         // key = peer_id, value = flags
76         core::map<u16, u8> peer_ids;
77 };
78
79 /*
80         This is a thread-safe class.
81 */
82 class BlockEmergeQueue
83 {
84 public:
85         BlockEmergeQueue()
86         {
87                 m_mutex.Init();
88         }
89
90         ~BlockEmergeQueue()
91         {
92                 JMutexAutoLock lock(m_mutex);
93
94                 core::list<QueuedBlockEmerge*>::Iterator i;
95                 for(i=m_queue.begin(); i!=m_queue.end(); i++)
96                 {
97                         QueuedBlockEmerge *q = *i;
98                         delete q;
99                 }
100         }
101         
102         /*
103                 peer_id=0 adds with nobody to send to
104         */
105         void addBlock(u16 peer_id, v3s16 pos, u8 flags)
106         {
107                 DSTACK(__FUNCTION_NAME);
108         
109                 JMutexAutoLock lock(m_mutex);
110
111                 if(peer_id != 0)
112                 {
113                         /*
114                                 Find if block is already in queue.
115                                 If it is, update the peer to it and quit.
116                         */
117                         core::list<QueuedBlockEmerge*>::Iterator i;
118                         for(i=m_queue.begin(); i!=m_queue.end(); i++)
119                         {
120                                 QueuedBlockEmerge *q = *i;
121                                 if(q->pos == pos)
122                                 {
123                                         q->peer_ids[peer_id] = flags;
124                                         return;
125                                 }
126                         }
127                 }
128                 
129                 /*
130                         Add the block
131                 */
132                 QueuedBlockEmerge *q = new QueuedBlockEmerge;
133                 q->pos = pos;
134                 if(peer_id != 0)
135                         q->peer_ids[peer_id] = flags;
136                 m_queue.push_back(q);
137         }
138
139         // Returned pointer must be deleted
140         // Returns NULL if queue is empty
141         QueuedBlockEmerge * pop()
142         {
143                 JMutexAutoLock lock(m_mutex);
144
145                 core::list<QueuedBlockEmerge*>::Iterator i = m_queue.begin();
146                 if(i == m_queue.end())
147                         return NULL;
148                 QueuedBlockEmerge *q = *i;
149                 m_queue.erase(i);
150                 return q;
151         }
152
153         u32 size()
154         {
155                 JMutexAutoLock lock(m_mutex);
156                 return m_queue.size();
157         }
158         
159         u32 peerItemCount(u16 peer_id)
160         {
161                 JMutexAutoLock lock(m_mutex);
162
163                 u32 count = 0;
164
165                 core::list<QueuedBlockEmerge*>::Iterator i;
166                 for(i=m_queue.begin(); i!=m_queue.end(); i++)
167                 {
168                         QueuedBlockEmerge *q = *i;
169                         if(q->peer_ids.find(peer_id) != NULL)
170                                 count++;
171                 }
172
173                 return count;
174         }
175
176 private:
177         core::list<QueuedBlockEmerge*> m_queue;
178         JMutex m_mutex;
179 };
180
181 class Server;
182
183 class ServerThread : public SimpleThread
184 {
185         Server *m_server;
186
187 public:
188
189         ServerThread(Server *server):
190                 SimpleThread(),
191                 m_server(server)
192         {
193         }
194
195         void * Thread();
196 };
197
198 class EmergeThread : public SimpleThread
199 {
200         Server *m_server;
201
202 public:
203
204         EmergeThread(Server *server):
205                 SimpleThread(),
206                 m_server(server)
207         {
208         }
209
210         void * Thread();
211
212         void trigger()
213         {
214                 setRun(true);
215                 if(IsRunning() == false)
216                 {
217                         Start();
218                 }
219         }
220 };
221
222 struct PlayerInfo
223 {
224         u16 id;
225         char name[PLAYERNAME_SIZE];
226         v3f position;
227         Address address;
228         float avg_rtt;
229
230         PlayerInfo();
231         void PrintLine(std::ostream *s);
232 };
233
234 /*
235         Used for queueing and sorting block transfers in containers
236         
237         Lower priority number means higher priority.
238 */
239 struct PrioritySortedBlockTransfer
240 {
241         PrioritySortedBlockTransfer(float a_priority, v3s16 a_pos, u16 a_peer_id)
242         {
243                 priority = a_priority;
244                 pos = a_pos;
245                 peer_id = a_peer_id;
246         }
247         bool operator < (PrioritySortedBlockTransfer &other)
248         {
249                 return priority < other.priority;
250         }
251         float priority;
252         v3s16 pos;
253         u16 peer_id;
254 };
255
256 struct MediaRequest
257 {
258         std::string name;
259
260         MediaRequest(const std::string &name_=""):
261                 name(name_)
262         {}
263 };
264
265 struct MediaInfo
266 {
267         std::string path;
268         std::string sha1_digest;
269
270         MediaInfo(const std::string path_="",
271                         const std::string sha1_digest_=""):
272                 path(path_),
273                 sha1_digest(sha1_digest_)
274         {
275         }
276 };
277
278 struct ServerSoundParams
279 {
280         float gain;
281         std::string to_player;
282         enum Type{
283                 SSP_LOCAL=0,
284                 SSP_POSITIONAL=1,
285                 SSP_OBJECT=2
286         } type;
287         v3f pos;
288         u16 object;
289         float max_hear_distance;
290         bool loop;
291
292         ServerSoundParams():
293                 gain(1.0),
294                 to_player(""),
295                 type(SSP_LOCAL),
296                 pos(0,0,0),
297                 object(0),
298                 max_hear_distance(32*BS),
299                 loop(false)
300         {}
301         
302         v3f getPos(ServerEnvironment *env, bool *pos_exists) const
303         {
304                 if(pos_exists) *pos_exists = false;
305                 switch(type){
306                 case SSP_LOCAL:
307                         return v3f(0,0,0);
308                 case SSP_POSITIONAL:
309                         if(pos_exists) *pos_exists = true;
310                         return pos;
311                 case SSP_OBJECT: {
312                         if(object == 0)
313                                 return v3f(0,0,0);
314                         ServerActiveObject *sao = env->getActiveObject(object);
315                         if(!sao)
316                                 return v3f(0,0,0);
317                         if(pos_exists) *pos_exists = true;
318                         return sao->getBasePosition(); }
319                 }
320                 return v3f(0,0,0);
321         }
322 };
323
324 struct ServerPlayingSound
325 {
326         ServerSoundParams params;
327         std::set<u16> clients; // peer ids
328 };
329
330 class RemoteClient
331 {
332 public:
333         // peer_id=0 means this client has no associated peer
334         // NOTE: If client is made allowed to exist while peer doesn't,
335         //       this has to be set to 0 when there is no peer.
336         //       Also, the client must be moved to some other container.
337         u16 peer_id;
338         // The serialization version to use with the client
339         u8 serialization_version;
340         //
341         u16 net_proto_version;
342         // Version is stored in here after INIT before INIT2
343         u8 pending_serialization_version;
344
345         bool definitions_sent;
346
347         RemoteClient():
348                 m_time_from_building(9999),
349                 m_excess_gotblocks(0)
350         {
351                 peer_id = 0;
352                 serialization_version = SER_FMT_VER_INVALID;
353                 net_proto_version = 0;
354                 pending_serialization_version = SER_FMT_VER_INVALID;
355                 definitions_sent = false;
356                 m_nearest_unsent_d = 0;
357                 m_nearest_unsent_reset_timer = 0.0;
358                 m_nothing_to_send_counter = 0;
359                 m_nothing_to_send_pause_timer = 0;
360         }
361         ~RemoteClient()
362         {
363         }
364         
365         /*
366                 Finds block that should be sent next to the client.
367                 Environment should be locked when this is called.
368                 dtime is used for resetting send radius at slow interval
369         */
370         void GetNextBlocks(Server *server, float dtime,
371                         core::array<PrioritySortedBlockTransfer> &dest);
372
373         void GotBlock(v3s16 p);
374
375         void SentBlock(v3s16 p);
376
377         void SetBlockNotSent(v3s16 p);
378         void SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks);
379
380         s32 SendingCount()
381         {
382                 return m_blocks_sending.size();
383         }
384         
385         // Increments timeouts and removes timed-out blocks from list
386         // NOTE: This doesn't fix the server-not-sending-block bug
387         //       because it is related to emerging, not sending.
388         //void RunSendingTimeouts(float dtime, float timeout);
389
390         void PrintInfo(std::ostream &o)
391         {
392                 o<<"RemoteClient "<<peer_id<<": "
393                                 <<"m_blocks_sent.size()="<<m_blocks_sent.size()
394                                 <<", m_blocks_sending.size()="<<m_blocks_sending.size()
395                                 <<", m_nearest_unsent_d="<<m_nearest_unsent_d
396                                 <<", m_excess_gotblocks="<<m_excess_gotblocks
397                                 <<std::endl;
398                 m_excess_gotblocks = 0;
399         }
400
401         // Time from last placing or removing blocks
402         float m_time_from_building;
403         
404         /*JMutex m_dig_mutex;
405         float m_dig_time_remaining;
406         // -1 = not digging
407         s16 m_dig_tool_item;
408         v3s16 m_dig_position;*/
409         
410         /*
411                 List of active objects that the client knows of.
412                 Value is dummy.
413         */
414         core::map<u16, bool> m_known_objects;
415
416 private:
417         /*
418                 Blocks that have been sent to client.
419                 - These don't have to be sent again.
420                 - A block is cleared from here when client says it has
421                   deleted it from it's memory
422                 
423                 Key is position, value is dummy.
424                 No MapBlock* is stored here because the blocks can get deleted.
425         */
426         core::map<v3s16, bool> m_blocks_sent;
427         s16 m_nearest_unsent_d;
428         v3s16 m_last_center;
429         float m_nearest_unsent_reset_timer;
430         
431         /*
432                 Blocks that are currently on the line.
433                 This is used for throttling the sending of blocks.
434                 - The size of this list is limited to some value
435                 Block is added when it is sent with BLOCKDATA.
436                 Block is removed when GOTBLOCKS is received.
437                 Value is time from sending. (not used at the moment)
438         */
439         core::map<v3s16, float> m_blocks_sending;
440
441         /*
442                 Count of excess GotBlocks().
443                 There is an excess amount because the client sometimes
444                 gets a block so late that the server sends it again,
445                 and the client then sends two GOTBLOCKs.
446                 This is resetted by PrintInfo()
447         */
448         u32 m_excess_gotblocks;
449         
450         // CPU usage optimization
451         u32 m_nothing_to_send_counter;
452         float m_nothing_to_send_pause_timer;
453 };
454
455 class Server : public con::PeerHandler, public MapEventReceiver,
456                 public InventoryManager, public IGameDef,
457                 public IBackgroundBlockEmerger
458 {
459 public:
460         /*
461                 NOTE: Every public method should be thread-safe
462         */
463         
464         Server(
465                 const std::string &path_world,
466                 const std::string &path_config,
467                 const SubgameSpec &gamespec,
468                 bool simple_singleplayer_mode
469         );
470         ~Server();
471         void start(unsigned short port);
472         void stop();
473         // This is mainly a way to pass the time to the server.
474         // Actual processing is done in an another thread.
475         void step(float dtime);
476         // This is run by ServerThread and does the actual processing
477         void AsyncRunStep();
478         void Receive();
479         void ProcessData(u8 *data, u32 datasize, u16 peer_id);
480
481         core::list<PlayerInfo> getPlayerInfo();
482
483         // Environment must be locked when called
484         void setTimeOfDay(u32 time)
485         {
486                 m_env->setTimeOfDay(time);
487                 m_time_of_day_send_timer = 0;
488         }
489
490         bool getShutdownRequested()
491         {
492                 return m_shutdown_requested;
493         }
494         
495         /*
496                 Shall be called with the environment locked.
497                 This is accessed by the map, which is inside the environment,
498                 so it shouldn't be a problem.
499         */
500         void onMapEditEvent(MapEditEvent *event);
501
502         /*
503                 Shall be called with the environment and the connection locked.
504         */
505         Inventory* getInventory(const InventoryLocation &loc);
506         std::string getInventoryOwner(const InventoryLocation &loc);
507         void setInventoryModified(const InventoryLocation &loc);
508
509         // Connection must be locked when called
510         std::wstring getStatusString();
511
512         void requestShutdown(void)
513         {
514                 m_shutdown_requested = true;
515         }
516
517         // Envlock and conlock should be locked when calling this
518         void SendMovePlayer(Player *player);
519         
520         // Returns -1 if failed, sound handle on success
521         // Envlock + conlock
522         s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams &params);
523         void stopSound(s32 handle);
524         
525         // Thread-safe
526         u64 getPlayerAuthPrivs(const std::string &name);
527         void setPlayerAuthPrivs(const std::string &name, u64 privs);
528         u64 getPlayerEffectivePrivs(const std::string &name);
529
530         // Changes a player's password, password must be given as plaintext
531         // If the player doesn't exist, a new entry is added to the auth manager
532         void setPlayerPassword(const std::string &name, const std::wstring &password);
533         
534         // Saves g_settings to configpath given at initialization
535         void saveConfig();
536
537         void setIpBanned(const std::string &ip, const std::string &name)
538         {
539                 m_banmanager.add(ip, name);
540                 return;
541         }
542
543         void unsetIpBanned(const std::string &ip_or_name)
544         {
545                 m_banmanager.remove(ip_or_name);
546                 return;
547         }
548
549         std::string getBanDescription(const std::string &ip_or_name)
550         {
551                 return m_banmanager.getBanDescription(ip_or_name);
552         }
553
554         Address getPeerAddress(u16 peer_id)
555         {
556                 return m_con.GetPeerAddress(peer_id);
557         }
558         
559         // Envlock and conlock should be locked when calling this
560         void notifyPlayer(const char *name, const std::wstring msg);
561         void notifyPlayers(const std::wstring msg);
562
563         void queueBlockEmerge(v3s16 blockpos, bool allow_generate);
564         
565         // Envlock and conlock should be locked when using Lua
566         lua_State *getLua(){ return m_lua; }
567         
568         // IGameDef interface
569         // Under envlock
570         virtual IItemDefManager* getItemDefManager();
571         virtual INodeDefManager* getNodeDefManager();
572         virtual ICraftDefManager* getCraftDefManager();
573         virtual ITextureSource* getTextureSource();
574         virtual u16 allocateUnknownNodeId(const std::string &name);
575         virtual ISoundManager* getSoundManager();
576         virtual MtEventManager* getEventManager();
577         
578         IWritableItemDefManager* getWritableItemDefManager();
579         IWritableNodeDefManager* getWritableNodeDefManager();
580         IWritableCraftDefManager* getWritableCraftDefManager();
581
582         const ModSpec* getModSpec(const std::string &modname);
583         
584         std::string getWorldPath(){ return m_path_world; }
585
586         void setAsyncFatalError(const std::string &error)
587         {
588                 m_async_fatal_error.set(error);
589         }
590
591 private:
592
593         // con::PeerHandler implementation.
594         // These queue stuff to be processed by handlePeerChanges().
595         // As of now, these create and remove clients and players.
596         void peerAdded(con::Peer *peer);
597         void deletingPeer(con::Peer *peer, bool timeout);
598         
599         /*
600                 Static send methods
601         */
602         
603         static void SendHP(con::Connection &con, u16 peer_id, u8 hp);
604         static void SendAccessDenied(con::Connection &con, u16 peer_id,
605                         const std::wstring &reason);
606         static void SendDeathscreen(con::Connection &con, u16 peer_id,
607                         bool set_camera_point_target, v3f camera_point_target);
608         static void SendItemDef(con::Connection &con, u16 peer_id,
609                         IItemDefManager *itemdef);
610         static void SendNodeDef(con::Connection &con, u16 peer_id,
611                         INodeDefManager *nodedef);
612         
613         /*
614                 Non-static send methods.
615                 Conlock should be always used.
616                 Envlock usage is documented badly but it's easy to figure out
617                 which ones access the environment.
618         */
619
620         // Envlock and conlock should be locked when calling these
621         void SendInventory(u16 peer_id);
622         // send wielded item info about player to all
623         void SendWieldedItem(const ServerRemotePlayer *srp);
624         // send wielded item info about all players to all players
625         void SendPlayerItems();
626         void SendChatMessage(u16 peer_id, const std::wstring &message);
627         void BroadcastChatMessage(const std::wstring &message);
628         void SendPlayerHP(Player *player);
629         /*
630                 Send a node removal/addition event to all clients except ignore_id.
631                 Additionally, if far_players!=NULL, players further away than
632                 far_d_nodes are ignored and their peer_ids are added to far_players
633         */
634         // Envlock and conlock should be locked when calling these
635         void sendRemoveNode(v3s16 p, u16 ignore_id=0,
636                         core::list<u16> *far_players=NULL, float far_d_nodes=100);
637         void sendAddNode(v3s16 p, MapNode n, u16 ignore_id=0,
638                         core::list<u16> *far_players=NULL, float far_d_nodes=100);
639         void setBlockNotSent(v3s16 p);
640         
641         // Environment and Connection must be locked when called
642         void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver);
643         
644         // Sends blocks to clients (locks env and con on its own)
645         void SendBlocks(float dtime);
646         
647         void fillMediaCache();
648         void sendMediaAnnouncement(u16 peer_id);
649         void sendRequestedMedia(u16 peer_id,
650                         const core::list<MediaRequest> &tosend);
651
652         /*
653                 Something random
654         */
655         
656         void DiePlayer(Player *player);
657         void RespawnPlayer(Player *player);
658         
659         void UpdateCrafting(u16 peer_id);
660         
661         // When called, connection mutex should be locked
662         RemoteClient* getClient(u16 peer_id);
663         
664         // When called, environment mutex should be locked
665         std::string getPlayerName(u16 peer_id)
666         {
667                 Player *player = m_env->getPlayer(peer_id);
668                 if(player == NULL)
669                         return "[id="+itos(peer_id)+"]";
670                 return player->getName();
671         }
672
673         /*
674                 Get a player from memory or creates one.
675                 If player is already connected, return NULL
676                 Does not verify/modify auth info and password.
677
678                 Call with env and con locked.
679         */
680         ServerRemotePlayer *emergePlayer(const char *name, u16 peer_id);
681         
682         // Locks environment and connection by its own
683         struct PeerChange;
684         void handlePeerChange(PeerChange &c);
685         void handlePeerChanges();
686
687         u64 getPlayerPrivs(Player *player);
688
689         /*
690                 Variables
691         */
692         
693         // World directory
694         std::string m_path_world;
695         // Path to user's configuration file ("" = no configuration file)
696         std::string m_path_config;
697         // Subgame specification
698         SubgameSpec m_gamespec;
699         // If true, do not allow multiple players and hide some multiplayer
700         // functionality
701         bool m_simple_singleplayer_mode;
702
703         // Thread can set; step() will throw as ServerError
704         MutexedVariable<std::string> m_async_fatal_error;
705         
706         // Some timers
707         float m_liquid_transform_timer;
708         float m_print_info_timer;
709         float m_objectdata_timer;
710         float m_emergethread_trigger_timer;
711         float m_savemap_timer;
712         IntervalLimiter m_map_timer_and_unload_interval;
713         
714         // NOTE: If connection and environment are both to be locked,
715         // environment shall be locked first.
716
717         // Environment
718         ServerEnvironment *m_env;
719         JMutex m_env_mutex;
720         
721         // Connection
722         con::Connection m_con;
723         JMutex m_con_mutex;
724         // Connected clients (behind the con mutex)
725         core::map<u16, RemoteClient*> m_clients;
726
727         // User authentication
728         AuthManager m_authmanager;
729
730         // Bann checking
731         BanManager m_banmanager;
732
733         // Scripting
734         // Envlock and conlock should be locked when using Lua
735         lua_State *m_lua;
736
737         // Item definition manager
738         IWritableItemDefManager *m_itemdef;
739         
740         // Node definition manager
741         IWritableNodeDefManager *m_nodedef;
742         
743         // Craft definition manager
744         IWritableCraftDefManager *m_craftdef;
745         
746         // Event manager
747         EventManager *m_event;
748         
749         // Mods
750         core::list<ModSpec> m_mods;
751         
752         /*
753                 Threads
754         */
755         
756         // A buffer for time steps
757         // step() increments and AsyncRunStep() run by m_thread reads it.
758         float m_step_dtime;
759         JMutex m_step_dtime_mutex;
760
761         // The server mainly operates in this thread
762         ServerThread m_thread;
763         // This thread fetches and generates map
764         EmergeThread m_emergethread;
765         // Queue of block coordinates to be processed by the emerge thread
766         BlockEmergeQueue m_emerge_queue;
767         
768         /*
769                 Time related stuff
770         */
771
772         // Timer for sending time of day over network
773         float m_time_of_day_send_timer;
774         // Uptime of server in seconds
775         MutexedVariable<double> m_uptime;
776         
777         /*
778                 Peer change queue.
779                 Queues stuff from peerAdded() and deletingPeer() to
780                 handlePeerChanges()
781         */
782         enum PeerChangeType
783         {
784                 PEER_ADDED,
785                 PEER_REMOVED
786         };
787         struct PeerChange
788         {
789                 PeerChangeType type;
790                 u16 peer_id;
791                 bool timeout;
792         };
793         Queue<PeerChange> m_peer_change_queue;
794
795         /*
796                 Random stuff
797         */
798         
799         // Mod parent directory paths
800         core::list<std::string> m_modspaths;
801
802         bool m_shutdown_requested;
803
804         /*
805                 Map edit event queue. Automatically receives all map edits.
806                 The constructor of this class registers us to receive them through
807                 onMapEditEvent
808
809                 NOTE: Should these be moved to actually be members of
810                 ServerEnvironment?
811         */
812
813         /*
814                 Queue of map edits from the environment for sending to the clients
815                 This is behind m_env_mutex
816         */
817         Queue<MapEditEvent*> m_unsent_map_edit_queue;
818         /*
819                 Set to true when the server itself is modifying the map and does
820                 all sending of information by itself.
821                 This is behind m_env_mutex
822         */
823         bool m_ignore_map_edit_events;
824         /*
825                 If set to !=0, the incoming MapEditEvents are modified to have
826                 this peed id as the disabled recipient
827                 This is behind m_env_mutex
828         */
829         u16 m_ignore_map_edit_events_peer_id;
830
831         friend class EmergeThread;
832         friend class RemoteClient;
833
834         std::map<std::string,MediaInfo> m_media;
835
836         /*
837                 Sounds
838         */
839         std::map<s32, ServerPlayingSound> m_playing_sounds;
840         s32 m_next_sound_id;
841 };
842
843 /*
844         Runs a simple dedicated server loop.
845
846         Shuts down when run is set to false.
847 */
848 void dedicated_server_loop(Server &server, bool &run);
849
850 #endif
851