Add online content repository
[oweals/minetest.git] / src / server.h
1 /*
2 Minetest
3 Copyright (C) 2010-2013 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser 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 #pragma once
21
22 #include "irr_v3d.h"
23 #include "map.h"
24 #include "hud.h"
25 #include "gamedef.h"
26 #include "serialization.h" // For SER_FMT_VER_INVALID
27 #include "content/mods.h"
28 #include "inventorymanager.h"
29 #include "content/subgames.h"
30 #include "tileanimation.h" // struct TileAnimationParams
31 #include "network/peerhandler.h"
32 #include "network/address.h"
33 #include "util/numeric.h"
34 #include "util/thread.h"
35 #include "util/basic_macros.h"
36 #include "serverenvironment.h"
37 #include "clientiface.h"
38 #include "chatmessage.h"
39 #include <string>
40 #include <list>
41 #include <map>
42 #include <vector>
43
44 class ChatEvent;
45 struct ChatEventChat;
46 struct ChatInterface;
47 class IWritableItemDefManager;
48 class NodeDefManager;
49 class IWritableCraftDefManager;
50 class BanManager;
51 class EventManager;
52 class Inventory;
53 class ModChannelMgr;
54 class RemotePlayer;
55 class PlayerSAO;
56 struct PlayerHPChangeReason;
57 class IRollbackManager;
58 struct RollbackAction;
59 class EmergeManager;
60 class ServerScripting;
61 class ServerEnvironment;
62 struct SimpleSoundSpec;
63 struct CloudParams;
64 class ServerThread;
65 class ServerModManager;
66
67 enum ClientDeletionReason {
68         CDR_LEAVE,
69         CDR_TIMEOUT,
70         CDR_DENY
71 };
72
73 struct MediaInfo
74 {
75         std::string path;
76         std::string sha1_digest;
77
78         MediaInfo(const std::string &path_="",
79                   const std::string &sha1_digest_=""):
80                 path(path_),
81                 sha1_digest(sha1_digest_)
82         {
83         }
84 };
85
86 struct ServerSoundParams
87 {
88         enum Type {
89                 SSP_LOCAL,
90                 SSP_POSITIONAL,
91                 SSP_OBJECT
92         } type = SSP_LOCAL;
93         float gain = 1.0f;
94         float fade = 0.0f;
95         float pitch = 1.0f;
96         bool loop = false;
97         float max_hear_distance = 32 * BS;
98         v3f pos;
99         u16 object = 0;
100         std::string to_player = "";
101
102         v3f getPos(ServerEnvironment *env, bool *pos_exists) const;
103 };
104
105 struct ServerPlayingSound
106 {
107         ServerSoundParams params;
108         SimpleSoundSpec spec;
109         std::unordered_set<session_t> clients; // peer ids
110 };
111
112 class Server : public con::PeerHandler, public MapEventReceiver,
113                 public InventoryManager, public IGameDef
114 {
115 public:
116         /*
117                 NOTE: Every public method should be thread-safe
118         */
119
120         Server(
121                 const std::string &path_world,
122                 const SubgameSpec &gamespec,
123                 bool simple_singleplayer_mode,
124                 Address bind_addr,
125                 bool dedicated,
126                 ChatInterface *iface = nullptr
127         );
128         ~Server();
129         DISABLE_CLASS_COPY(Server);
130
131         void start();
132         void stop();
133         // This is mainly a way to pass the time to the server.
134         // Actual processing is done in an another thread.
135         void step(float dtime);
136         // This is run by ServerThread and does the actual processing
137         void AsyncRunStep(bool initial_step=false);
138         void Receive();
139         PlayerSAO* StageTwoClientInit(session_t peer_id);
140
141         /*
142          * Command Handlers
143          */
144
145         void handleCommand(NetworkPacket* pkt);
146
147         void handleCommand_Null(NetworkPacket* pkt) {};
148         void handleCommand_Deprecated(NetworkPacket* pkt);
149         void handleCommand_Init(NetworkPacket* pkt);
150         void handleCommand_Init2(NetworkPacket* pkt);
151         void handleCommand_ModChannelJoin(NetworkPacket *pkt);
152         void handleCommand_ModChannelLeave(NetworkPacket *pkt);
153         void handleCommand_ModChannelMsg(NetworkPacket *pkt);
154         void handleCommand_RequestMedia(NetworkPacket* pkt);
155         void handleCommand_ClientReady(NetworkPacket* pkt);
156         void handleCommand_GotBlocks(NetworkPacket* pkt);
157         void handleCommand_PlayerPos(NetworkPacket* pkt);
158         void handleCommand_DeletedBlocks(NetworkPacket* pkt);
159         void handleCommand_InventoryAction(NetworkPacket* pkt);
160         void handleCommand_ChatMessage(NetworkPacket* pkt);
161         void handleCommand_Damage(NetworkPacket* pkt);
162         void handleCommand_Password(NetworkPacket* pkt);
163         void handleCommand_PlayerItem(NetworkPacket* pkt);
164         void handleCommand_Respawn(NetworkPacket* pkt);
165         void handleCommand_Interact(NetworkPacket* pkt);
166         void handleCommand_RemovedSounds(NetworkPacket* pkt);
167         void handleCommand_NodeMetaFields(NetworkPacket* pkt);
168         void handleCommand_InventoryFields(NetworkPacket* pkt);
169         void handleCommand_FirstSrp(NetworkPacket* pkt);
170         void handleCommand_SrpBytesA(NetworkPacket* pkt);
171         void handleCommand_SrpBytesM(NetworkPacket* pkt);
172
173         void ProcessData(NetworkPacket *pkt);
174
175         void Send(NetworkPacket *pkt);
176         void Send(session_t peer_id, NetworkPacket *pkt);
177
178         // Helper for handleCommand_PlayerPos and handleCommand_Interact
179         void process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
180                 NetworkPacket *pkt);
181
182         // Both setter and getter need no envlock,
183         // can be called freely from threads
184         void setTimeOfDay(u32 time);
185
186         /*
187                 Shall be called with the environment locked.
188                 This is accessed by the map, which is inside the environment,
189                 so it shouldn't be a problem.
190         */
191         void onMapEditEvent(MapEditEvent *event);
192
193         /*
194                 Shall be called with the environment and the connection locked.
195         */
196         Inventory* getInventory(const InventoryLocation &loc);
197         void setInventoryModified(const InventoryLocation &loc, bool playerSend = true);
198
199         // Connection must be locked when called
200         std::wstring getStatusString();
201         inline double getUptime() const { return m_uptime.m_value; }
202
203         // read shutdown state
204         inline bool getShutdownRequested() const { return m_shutdown_requested; }
205
206         // request server to shutdown
207         void requestShutdown(const std::string &msg, bool reconnect, float delay = 0.0f);
208
209         // Returns -1 if failed, sound handle on success
210         // Envlock
211         s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams &params);
212         void stopSound(s32 handle);
213         void fadeSound(s32 handle, float step, float gain);
214
215         // Envlock
216         std::set<std::string> getPlayerEffectivePrivs(const std::string &name);
217         bool checkPriv(const std::string &name, const std::string &priv);
218         void reportPrivsModified(const std::string &name=""); // ""=all
219         void reportInventoryFormspecModified(const std::string &name);
220         void reportFormspecPrependModified(const std::string &name);
221
222         void setIpBanned(const std::string &ip, const std::string &name);
223         void unsetIpBanned(const std::string &ip_or_name);
224         std::string getBanDescription(const std::string &ip_or_name);
225
226         void notifyPlayer(const char *name, const std::wstring &msg);
227         void notifyPlayers(const std::wstring &msg);
228         void spawnParticle(const std::string &playername,
229                 v3f pos, v3f velocity, v3f acceleration,
230                 float expirationtime, float size,
231                 bool collisiondetection, bool collision_removal,
232                 bool vertical, const std::string &texture,
233                 const struct TileAnimationParams &animation, u8 glow);
234
235         u32 addParticleSpawner(u16 amount, float spawntime,
236                 v3f minpos, v3f maxpos,
237                 v3f minvel, v3f maxvel,
238                 v3f minacc, v3f maxacc,
239                 float minexptime, float maxexptime,
240                 float minsize, float maxsize,
241                 bool collisiondetection, bool collision_removal,
242                 ServerActiveObject *attached,
243                 bool vertical, const std::string &texture,
244                 const std::string &playername, const struct TileAnimationParams &animation,
245                 u8 glow);
246
247         void deleteParticleSpawner(const std::string &playername, u32 id);
248
249         // Creates or resets inventory
250         Inventory* createDetachedInventory(const std::string &name, const std::string &player="");
251
252         // Envlock and conlock should be locked when using scriptapi
253         ServerScripting *getScriptIface(){ return m_script; }
254
255         // actions: time-reversed list
256         // Return value: success/failure
257         bool rollbackRevertActions(const std::list<RollbackAction> &actions,
258                         std::list<std::string> *log);
259
260         // IGameDef interface
261         // Under envlock
262         virtual IItemDefManager* getItemDefManager();
263         virtual const NodeDefManager* getNodeDefManager();
264         virtual ICraftDefManager* getCraftDefManager();
265         virtual u16 allocateUnknownNodeId(const std::string &name);
266         IRollbackManager *getRollbackManager() { return m_rollback; }
267         virtual EmergeManager *getEmergeManager() { return m_emerge; }
268
269         IWritableItemDefManager* getWritableItemDefManager();
270         NodeDefManager* getWritableNodeDefManager();
271         IWritableCraftDefManager* getWritableCraftDefManager();
272
273         virtual const std::vector<ModSpec> &getMods() const;
274         virtual const ModSpec* getModSpec(const std::string &modname) const;
275         void getModNames(std::vector<std::string> &modlist);
276         std::string getBuiltinLuaPath();
277         virtual std::string getWorldPath() const { return m_path_world; }
278         virtual std::string getModStoragePath() const;
279
280         inline bool isSingleplayer()
281                         { return m_simple_singleplayer_mode; }
282
283         inline void setAsyncFatalError(const std::string &error)
284                         { m_async_fatal_error.set(error); }
285
286         bool showFormspec(const char *name, const std::string &formspec, const std::string &formname);
287         Map & getMap() { return m_env->getMap(); }
288         ServerEnvironment & getEnv() { return *m_env; }
289         v3f findSpawnPos();
290
291         u32 hudAdd(RemotePlayer *player, HudElement *element);
292         bool hudRemove(RemotePlayer *player, u32 id);
293         bool hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *value);
294         bool hudSetFlags(RemotePlayer *player, u32 flags, u32 mask);
295         bool hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount);
296         void hudSetHotbarImage(RemotePlayer *player, std::string name);
297         void hudSetHotbarSelectedImage(RemotePlayer *player, std::string name);
298
299         Address getPeerAddress(session_t peer_id);
300
301         void setLocalPlayerAnimations(RemotePlayer *player, v2s32 animation_frames[4],
302                         f32 frame_speed);
303         void setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third);
304
305         void setSky(RemotePlayer *player, const video::SColor &bgcolor,
306                         const std::string &type, const std::vector<std::string> &params,
307                         bool &clouds);
308         void setClouds(RemotePlayer *player, const CloudParams &params);
309
310         bool overrideDayNightRatio(RemotePlayer *player, bool do_override, float brightness);
311
312         /* con::PeerHandler implementation. */
313         void peerAdded(con::Peer *peer);
314         void deletingPeer(con::Peer *peer, bool timeout);
315
316         void DenySudoAccess(session_t peer_id);
317         void DenyAccessVerCompliant(session_t peer_id, u16 proto_ver, AccessDeniedCode reason,
318                 const std::string &str_reason = "", bool reconnect = false);
319         void DenyAccess(session_t peer_id, AccessDeniedCode reason,
320                 const std::string &custom_reason = "");
321         void acceptAuth(session_t peer_id, bool forSudoMode);
322         void DenyAccess_Legacy(session_t peer_id, const std::wstring &reason);
323         void DisconnectPeer(session_t peer_id);
324         bool getClientConInfo(session_t peer_id, con::rtt_stat_type type, float *retval);
325         bool getClientInfo(session_t peer_id, ClientState *state, u32 *uptime,
326                         u8* ser_vers, u16* prot_vers, u8* major, u8* minor, u8* patch,
327                         std::string* vers_string);
328
329         void printToConsoleOnly(const std::string &text);
330
331         void SendPlayerHPOrDie(PlayerSAO *player, const PlayerHPChangeReason &reason);
332         void SendPlayerBreath(PlayerSAO *sao);
333         void SendInventory(PlayerSAO* playerSAO);
334         void SendMovePlayer(session_t peer_id);
335
336         virtual bool registerModStorage(ModMetadata *storage);
337         virtual void unregisterModStorage(const std::string &name);
338
339         bool joinModChannel(const std::string &channel);
340         bool leaveModChannel(const std::string &channel);
341         bool sendModChannelMessage(const std::string &channel, const std::string &message);
342         ModChannel *getModChannel(const std::string &channel);
343
344         // Bind address
345         Address m_bind_addr;
346
347         // Environment mutex (envlock)
348         std::mutex m_env_mutex;
349
350 private:
351
352         friend class EmergeThread;
353         friend class RemoteClient;
354
355         void SendMovement(session_t peer_id);
356         void SendHP(session_t peer_id, u16 hp);
357         void SendBreath(session_t peer_id, u16 breath);
358         void SendAccessDenied(session_t peer_id, AccessDeniedCode reason,
359                 const std::string &custom_reason, bool reconnect = false);
360         void SendAccessDenied_Legacy(session_t peer_id, const std::wstring &reason);
361         void SendDeathscreen(session_t peer_id, bool set_camera_point_target,
362                 v3f camera_point_target);
363         void SendItemDef(session_t peer_id, IItemDefManager *itemdef, u16 protocol_version);
364         void SendNodeDef(session_t peer_id, const NodeDefManager *nodedef,
365                 u16 protocol_version);
366
367         /* mark blocks not sent for all clients */
368         void SetBlocksNotSent(std::map<v3s16, MapBlock *>& block);
369
370
371         void SendChatMessage(session_t peer_id, const ChatMessage &message);
372         void SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed);
373         void SendPlayerHP(session_t peer_id);
374
375         void SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4],
376                 f32 animation_speed);
377         void SendEyeOffset(session_t peer_id, v3f first, v3f third);
378         void SendPlayerPrivileges(session_t peer_id);
379         void SendPlayerInventoryFormspec(session_t peer_id);
380         void SendPlayerFormspecPrepend(session_t peer_id);
381         void SendShowFormspecMessage(session_t peer_id, const std::string &formspec,
382                 const std::string &formname);
383         void SendHUDAdd(session_t peer_id, u32 id, HudElement *form);
384         void SendHUDRemove(session_t peer_id, u32 id);
385         void SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value);
386         void SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask);
387         void SendHUDSetParam(session_t peer_id, u16 param, const std::string &value);
388         void SendSetSky(session_t peer_id, const video::SColor &bgcolor,
389                         const std::string &type, const std::vector<std::string> &params,
390                         bool &clouds);
391         void SendCloudParams(session_t peer_id, const CloudParams &params);
392         void SendOverrideDayNightRatio(session_t peer_id, bool do_override, float ratio);
393         void broadcastModChannelMessage(const std::string &channel,
394                         const std::string &message, session_t from_peer);
395
396         /*
397                 Send a node removal/addition event to all clients except ignore_id.
398                 Additionally, if far_players!=NULL, players further away than
399                 far_d_nodes are ignored and their peer_ids are added to far_players
400         */
401         // Envlock and conlock should be locked when calling these
402         void sendRemoveNode(v3s16 p, u16 ignore_id=0,
403                         std::vector<u16> *far_players=NULL, float far_d_nodes=100);
404         void sendAddNode(v3s16 p, MapNode n, u16 ignore_id=0,
405                         std::vector<u16> *far_players=NULL, float far_d_nodes=100,
406                         bool remove_metadata=true);
407
408         // Environment and Connection must be locked when called
409         void SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver, u16 net_proto_version);
410
411         // Sends blocks to clients (locks env and con on its own)
412         void SendBlocks(float dtime);
413
414         void fillMediaCache();
415         void sendMediaAnnouncement(session_t peer_id, const std::string &lang_code);
416         void sendRequestedMedia(session_t peer_id,
417                         const std::vector<std::string> &tosend);
418
419         void sendDetachedInventory(const std::string &name, session_t peer_id);
420         void sendDetachedInventories(session_t peer_id);
421
422         // Adds a ParticleSpawner on peer with peer_id (PEER_ID_INEXISTENT == all)
423         void SendAddParticleSpawner(session_t peer_id, u16 protocol_version,
424                 u16 amount, float spawntime,
425                 v3f minpos, v3f maxpos,
426                 v3f minvel, v3f maxvel,
427                 v3f minacc, v3f maxacc,
428                 float minexptime, float maxexptime,
429                 float minsize, float maxsize,
430                 bool collisiondetection, bool collision_removal,
431                 u16 attached_id,
432                 bool vertical, const std::string &texture, u32 id,
433                 const struct TileAnimationParams &animation, u8 glow);
434
435         void SendDeleteParticleSpawner(session_t peer_id, u32 id);
436
437         // Spawns particle on peer with peer_id (PEER_ID_INEXISTENT == all)
438         void SendSpawnParticle(session_t peer_id, u16 protocol_version,
439                 v3f pos, v3f velocity, v3f acceleration,
440                 float expirationtime, float size,
441                 bool collisiondetection, bool collision_removal,
442                 bool vertical, const std::string &texture,
443                 const struct TileAnimationParams &animation, u8 glow);
444
445         u32 SendActiveObjectRemoveAdd(session_t peer_id, const std::string &datas);
446         void SendActiveObjectMessages(session_t peer_id, const std::string &datas,
447                 bool reliable = true);
448         void SendCSMFlavourLimits(session_t peer_id);
449
450         /*
451                 Something random
452         */
453
454         void DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason);
455         void RespawnPlayer(session_t peer_id);
456         void DeleteClient(session_t peer_id, ClientDeletionReason reason);
457         void UpdateCrafting(RemotePlayer *player);
458         bool checkInteractDistance(RemotePlayer *player, const f32 d, const std::string what);
459
460         void handleChatInterfaceEvent(ChatEvent *evt);
461
462         // This returns the answer to the sender of wmessage, or "" if there is none
463         std::wstring handleChat(const std::string &name, const std::wstring &wname,
464                 std::wstring wmessage_input,
465                 bool check_shout_priv = false,
466                 RemotePlayer *player = NULL);
467         void handleAdminChat(const ChatEventChat *evt);
468
469         // When called, connection mutex should be locked
470         RemoteClient* getClient(session_t peer_id, ClientState state_min = CS_Active);
471         RemoteClient* getClientNoEx(session_t peer_id, ClientState state_min = CS_Active);
472
473         // When called, environment mutex should be locked
474         std::string getPlayerName(session_t peer_id);
475         PlayerSAO *getPlayerSAO(session_t peer_id);
476
477         /*
478                 Get a player from memory or creates one.
479                 If player is already connected, return NULL
480                 Does not verify/modify auth info and password.
481
482                 Call with env and con locked.
483         */
484         PlayerSAO *emergePlayer(const char *name, session_t peer_id, u16 proto_version);
485
486         void handlePeerChanges();
487
488         /*
489                 Variables
490         */
491
492         // World directory
493         std::string m_path_world;
494         // Subgame specification
495         SubgameSpec m_gamespec;
496         // If true, do not allow multiple players and hide some multiplayer
497         // functionality
498         bool m_simple_singleplayer_mode;
499         u16 m_max_chatmessage_length;
500         // For "dedicated" server list flag
501         bool m_dedicated;
502
503         // Thread can set; step() will throw as ServerError
504         MutexedVariable<std::string> m_async_fatal_error;
505
506         // Some timers
507         float m_liquid_transform_timer = 0.0f;
508         float m_liquid_transform_every = 1.0f;
509         float m_masterserver_timer = 0.0f;
510         float m_emergethread_trigger_timer = 0.0f;
511         float m_savemap_timer = 0.0f;
512         IntervalLimiter m_map_timer_and_unload_interval;
513
514         // Environment
515         ServerEnvironment *m_env = nullptr;
516
517         // server connection
518         std::shared_ptr<con::Connection> m_con;
519
520         // Ban checking
521         BanManager *m_banmanager = nullptr;
522
523         // Rollback manager (behind m_env_mutex)
524         IRollbackManager *m_rollback = nullptr;
525
526         // Emerge manager
527         EmergeManager *m_emerge = nullptr;
528
529         // Scripting
530         // Envlock and conlock should be locked when using Lua
531         ServerScripting *m_script = nullptr;
532
533         // Item definition manager
534         IWritableItemDefManager *m_itemdef;
535
536         // Node definition manager
537         NodeDefManager *m_nodedef;
538
539         // Craft definition manager
540         IWritableCraftDefManager *m_craftdef;
541
542         // Event manager
543         EventManager *m_event;
544
545         // Mods
546         std::unique_ptr<ServerModManager> m_modmgr;
547
548         /*
549                 Threads
550         */
551
552         // A buffer for time steps
553         // step() increments and AsyncRunStep() run by m_thread reads it.
554         float m_step_dtime = 0.0f;
555         std::mutex m_step_dtime_mutex;
556
557         // current server step lag counter
558         float m_lag;
559
560         // The server mainly operates in this thread
561         ServerThread *m_thread = nullptr;
562
563         /*
564                 Time related stuff
565         */
566
567         // Timer for sending time of day over network
568         float m_time_of_day_send_timer = 0.0f;
569         // Uptime of server in seconds
570         MutexedVariable<double> m_uptime;
571         /*
572          Client interface
573          */
574         ClientInterface m_clients;
575
576         /*
577                 Peer change queue.
578                 Queues stuff from peerAdded() and deletingPeer() to
579                 handlePeerChanges()
580         */
581         std::queue<con::PeerChange> m_peer_change_queue;
582
583         std::unordered_map<session_t, std::string> m_formspec_state_data;
584
585         /*
586                 Random stuff
587         */
588
589         bool m_shutdown_requested = false;
590         std::string m_shutdown_msg;
591         bool m_shutdown_ask_reconnect = false;
592         float m_shutdown_timer = 0.0f;
593
594         ChatInterface *m_admin_chat;
595         std::string m_admin_nick;
596
597         /*
598                 Map edit event queue. Automatically receives all map edits.
599                 The constructor of this class registers us to receive them through
600                 onMapEditEvent
601
602                 NOTE: Should these be moved to actually be members of
603                 ServerEnvironment?
604         */
605
606         /*
607                 Queue of map edits from the environment for sending to the clients
608                 This is behind m_env_mutex
609         */
610         std::queue<MapEditEvent*> m_unsent_map_edit_queue;
611         /*
612                 Set to true when the server itself is modifying the map and does
613                 all sending of information by itself.
614                 This is behind m_env_mutex
615         */
616         bool m_ignore_map_edit_events = false;
617         /*
618                 If a non-empty area, map edit events contained within are left
619                 unsent. Done at map generation time to speed up editing of the
620                 generated area, as it will be sent anyway.
621                 This is behind m_env_mutex
622         */
623         VoxelArea m_ignore_map_edit_events_area;
624
625         // media files known to server
626         std::unordered_map<std::string, MediaInfo> m_media;
627
628         /*
629                 Sounds
630         */
631         std::unordered_map<s32, ServerPlayingSound> m_playing_sounds;
632         s32 m_next_sound_id = 0;
633
634         /*
635                 Detached inventories (behind m_env_mutex)
636         */
637         // key = name
638         std::map<std::string, Inventory*> m_detached_inventories;
639         // value = "" (visible to all players) or player name
640         std::map<std::string, std::string> m_detached_inventories_player;
641
642         std::unordered_map<std::string, ModMetadata *> m_mod_storages;
643         float m_mod_storage_save_timer = 10.0f;
644
645         // CSM flavour limits byteflag
646         u64 m_csm_flavour_limits = CSMFlavourLimit::CSM_FL_NONE;
647         u32 m_csm_noderange_limit = 8;
648
649         // ModChannel manager
650         std::unique_ptr<ModChannelMgr> m_modchannel_mgr;
651 };
652
653 /*
654         Runs a simple dedicated server loop.
655
656         Shuts down when kill is set to true.
657 */
658 void dedicated_server_loop(Server &server, bool &kill);