Add formspec theming using prepended strings
[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 "mods.h"
28 #include "inventorymanager.h"
29 #include "subgame.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 class IRollbackManager;
57 struct RollbackAction;
58 class EmergeManager;
59 class ServerScripting;
60 class ServerEnvironment;
61 struct SimpleSoundSpec;
62 struct CloudParams;
63 class ServerThread;
64 class ServerModManager;
65
66 enum ClientDeletionReason {
67         CDR_LEAVE,
68         CDR_TIMEOUT,
69         CDR_DENY
70 };
71
72 struct MediaInfo
73 {
74         std::string path;
75         std::string sha1_digest;
76
77         MediaInfo(const std::string &path_="",
78                   const std::string &sha1_digest_=""):
79                 path(path_),
80                 sha1_digest(sha1_digest_)
81         {
82         }
83 };
84
85 struct ServerSoundParams
86 {
87         enum Type {
88                 SSP_LOCAL,
89                 SSP_POSITIONAL,
90                 SSP_OBJECT
91         } type = SSP_LOCAL;
92         float gain = 1.0f;
93         float fade = 0.0f;
94         float pitch = 1.0f;
95         bool loop = false;
96         float max_hear_distance = 32 * BS;
97         v3f pos;
98         u16 object = 0;
99         std::string to_player = "";
100
101         v3f getPos(ServerEnvironment *env, bool *pos_exists) const;
102 };
103
104 struct ServerPlayingSound
105 {
106         ServerSoundParams params;
107         SimpleSoundSpec spec;
108         std::unordered_set<session_t> clients; // peer ids
109 };
110
111 class Server : public con::PeerHandler, public MapEventReceiver,
112                 public InventoryManager, public IGameDef
113 {
114 public:
115         /*
116                 NOTE: Every public method should be thread-safe
117         */
118
119         Server(
120                 const std::string &path_world,
121                 const SubgameSpec &gamespec,
122                 bool simple_singleplayer_mode,
123                 Address bind_addr,
124                 bool dedicated,
125                 ChatInterface *iface = nullptr
126         );
127         ~Server();
128         DISABLE_CLASS_COPY(Server);
129
130         void start();
131         void stop();
132         // This is mainly a way to pass the time to the server.
133         // Actual processing is done in an another thread.
134         void step(float dtime);
135         // This is run by ServerThread and does the actual processing
136         void AsyncRunStep(bool initial_step=false);
137         void Receive();
138         PlayerSAO* StageTwoClientInit(session_t peer_id);
139
140         /*
141          * Command Handlers
142          */
143
144         void handleCommand(NetworkPacket* pkt);
145
146         void handleCommand_Null(NetworkPacket* pkt) {};
147         void handleCommand_Deprecated(NetworkPacket* pkt);
148         void handleCommand_Init(NetworkPacket* pkt);
149         void handleCommand_Init2(NetworkPacket* pkt);
150         void handleCommand_ModChannelJoin(NetworkPacket *pkt);
151         void handleCommand_ModChannelLeave(NetworkPacket *pkt);
152         void handleCommand_ModChannelMsg(NetworkPacket *pkt);
153         void handleCommand_RequestMedia(NetworkPacket* pkt);
154         void handleCommand_ClientReady(NetworkPacket* pkt);
155         void handleCommand_GotBlocks(NetworkPacket* pkt);
156         void handleCommand_PlayerPos(NetworkPacket* pkt);
157         void handleCommand_DeletedBlocks(NetworkPacket* pkt);
158         void handleCommand_InventoryAction(NetworkPacket* pkt);
159         void handleCommand_ChatMessage(NetworkPacket* pkt);
160         void handleCommand_Damage(NetworkPacket* pkt);
161         void handleCommand_Password(NetworkPacket* pkt);
162         void handleCommand_PlayerItem(NetworkPacket* pkt);
163         void handleCommand_Respawn(NetworkPacket* pkt);
164         void handleCommand_Interact(NetworkPacket* pkt);
165         void handleCommand_RemovedSounds(NetworkPacket* pkt);
166         void handleCommand_NodeMetaFields(NetworkPacket* pkt);
167         void handleCommand_InventoryFields(NetworkPacket* pkt);
168         void handleCommand_FirstSrp(NetworkPacket* pkt);
169         void handleCommand_SrpBytesA(NetworkPacket* pkt);
170         void handleCommand_SrpBytesM(NetworkPacket* pkt);
171
172         void ProcessData(NetworkPacket *pkt);
173
174         void Send(NetworkPacket *pkt);
175         void Send(session_t peer_id, NetworkPacket *pkt);
176
177         // Helper for handleCommand_PlayerPos and handleCommand_Interact
178         void process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
179                 NetworkPacket *pkt);
180
181         // Both setter and getter need no envlock,
182         // can be called freely from threads
183         void setTimeOfDay(u32 time);
184
185         /*
186                 Shall be called with the environment locked.
187                 This is accessed by the map, which is inside the environment,
188                 so it shouldn't be a problem.
189         */
190         void onMapEditEvent(MapEditEvent *event);
191
192         /*
193                 Shall be called with the environment and the connection locked.
194         */
195         Inventory* getInventory(const InventoryLocation &loc);
196         void setInventoryModified(const InventoryLocation &loc, bool playerSend = true);
197
198         // Connection must be locked when called
199         std::wstring getStatusString();
200         inline double getUptime() const { return m_uptime.m_value; }
201
202         // read shutdown state
203         inline bool getShutdownRequested() const { return m_shutdown_requested; }
204
205         // request server to shutdown
206         void requestShutdown(const std::string &msg, bool reconnect, float delay = 0.0f);
207
208         // Returns -1 if failed, sound handle on success
209         // Envlock
210         s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams &params);
211         void stopSound(s32 handle);
212         void fadeSound(s32 handle, float step, float gain);
213
214         // Envlock
215         std::set<std::string> getPlayerEffectivePrivs(const std::string &name);
216         bool checkPriv(const std::string &name, const std::string &priv);
217         void reportPrivsModified(const std::string &name=""); // ""=all
218         void reportInventoryFormspecModified(const std::string &name);
219         void reportFormspecPrependModified(const std::string &name);
220
221         void setIpBanned(const std::string &ip, const std::string &name);
222         void unsetIpBanned(const std::string &ip_or_name);
223         std::string getBanDescription(const std::string &ip_or_name);
224
225         void notifyPlayer(const char *name, const std::wstring &msg);
226         void notifyPlayers(const std::wstring &msg);
227         void spawnParticle(const std::string &playername,
228                 v3f pos, v3f velocity, v3f acceleration,
229                 float expirationtime, float size,
230                 bool collisiondetection, bool collision_removal,
231                 bool vertical, const std::string &texture,
232                 const struct TileAnimationParams &animation, u8 glow);
233
234         u32 addParticleSpawner(u16 amount, float spawntime,
235                 v3f minpos, v3f maxpos,
236                 v3f minvel, v3f maxvel,
237                 v3f minacc, v3f maxacc,
238                 float minexptime, float maxexptime,
239                 float minsize, float maxsize,
240                 bool collisiondetection, bool collision_removal,
241                 ServerActiveObject *attached,
242                 bool vertical, const std::string &texture,
243                 const std::string &playername, const struct TileAnimationParams &animation,
244                 u8 glow);
245
246         void deleteParticleSpawner(const std::string &playername, u32 id);
247
248         // Creates or resets inventory
249         Inventory* createDetachedInventory(const std::string &name, const std::string &player="");
250
251         // Envlock and conlock should be locked when using scriptapi
252         ServerScripting *getScriptIface(){ return m_script; }
253
254         // actions: time-reversed list
255         // Return value: success/failure
256         bool rollbackRevertActions(const std::list<RollbackAction> &actions,
257                         std::list<std::string> *log);
258
259         // IGameDef interface
260         // Under envlock
261         virtual IItemDefManager* getItemDefManager();
262         virtual const NodeDefManager* getNodeDefManager();
263         virtual ICraftDefManager* getCraftDefManager();
264         virtual u16 allocateUnknownNodeId(const std::string &name);
265         virtual MtEventManager* getEventManager();
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);
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);
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);