diff options
Diffstat (limited to 'src/server.h')
-rw-r--r-- | src/server.h | 1017 |
1 files changed, 459 insertions, 558 deletions
diff --git a/src/server.h b/src/server.h index 12520a1d7..cb7d77067 100644 --- a/src/server.h +++ b/src/server.h @@ -17,326 +17,125 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef SERVER_HEADER -#define SERVER_HEADER +#pragma once -#include "connection.h" #include "irr_v3d.h" #include "map.h" #include "hud.h" #include "gamedef.h" #include "serialization.h" // For SER_FMT_VER_INVALID -#include "mods.h" +#include "content/mods.h" #include "inventorymanager.h" -#include "subgame.h" -#include "rollback_interface.h" // Needed for rollbackRevertActions() +#include "content/subgames.h" +#include "tileanimation.h" // TileAnimationParams +#include "particles.h" // ParticleParams +#include "network/peerhandler.h" +#include "network/address.h" #include "util/numeric.h" #include "util/thread.h" +#include "util/basic_macros.h" +#include "util/metricsbackend.h" +#include "serverenvironment.h" +#include "clientiface.h" +#include "chatmessage.h" +#include "translation.h" #include <string> #include <list> #include <map> #include <vector> +#include <unordered_set> -#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" - +class ChatEvent; +struct ChatEventChat; +struct ChatInterface; class IWritableItemDefManager; -class IWritableNodeDefManager; +class NodeDefManager; class IWritableCraftDefManager; class BanManager; class EventManager; class Inventory; -class Player; +class ModChannelMgr; +class RemotePlayer; class PlayerSAO; +struct PlayerHPChangeReason; class IRollbackManager; +struct RollbackAction; class EmergeManager; -class GameScripting; +class ServerScripting; class ServerEnvironment; struct SimpleSoundSpec; - - -class ServerError : public std::exception -{ -public: - ServerError(const std::string &s) - { - m_s = "ServerError: "; - m_s += s; - } - virtual ~ServerError() throw() - {} - virtual const char * what() const throw() - { - return m_s.c_str(); - } - std::string m_s; -}; - -/* - Some random functions -*/ -v3f findSpawnPos(ServerMap &map); - - -class MapEditEventIgnorer -{ -public: - MapEditEventIgnorer(bool *flag): - m_flag(flag) - { - if(*m_flag == false) - *m_flag = true; - else - m_flag = NULL; - } - - ~MapEditEventIgnorer() - { - if(m_flag) - { - assert(*m_flag); - *m_flag = false; - } - } - -private: - bool *m_flag; -}; - -class MapEditEventAreaIgnorer -{ -public: - MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a): - m_ignorevariable(ignorevariable) - { - if(m_ignorevariable->getVolume() == 0) - *m_ignorevariable = a; - else - m_ignorevariable = NULL; - } - - ~MapEditEventAreaIgnorer() - { - if(m_ignorevariable) - { - assert(m_ignorevariable->getVolume() != 0); - *m_ignorevariable = VoxelArea(); - } - } - -private: - VoxelArea *m_ignorevariable; -}; - -class Server; +struct CloudParams; +struct SkyboxParams; +struct SunParams; +struct MoonParams; +struct StarParams; +struct Lighting; class ServerThread; - -/* - Used for queueing and sorting block transfers in containers - - Lower priority number means higher priority. -*/ -struct PrioritySortedBlockTransfer -{ - PrioritySortedBlockTransfer(float a_priority, v3s16 a_pos, u16 a_peer_id) - { - priority = a_priority; - pos = a_pos; - peer_id = a_peer_id; - } - bool operator < (const PrioritySortedBlockTransfer &other) const - { - return priority < other.priority; - } - float priority; - v3s16 pos; - u16 peer_id; -}; - -struct MediaRequest -{ - std::string name; - - MediaRequest(const std::string &name_=""): - name(name_) - {} +class ServerModManager; +class ServerInventoryManager; +struct PackedValue; + +enum ClientDeletionReason { + CDR_LEAVE, + CDR_TIMEOUT, + CDR_DENY }; struct MediaInfo { std::string path; - std::string sha1_digest; + std::string sha1_digest; // base64-encoded + bool no_announce; // true: not announced in TOCLIENT_ANNOUNCE_MEDIA (at player join) - MediaInfo(const std::string path_="", - const std::string sha1_digest_=""): + MediaInfo(const std::string &path_="", + const std::string &sha1_digest_=""): path(path_), - sha1_digest(sha1_digest_) + sha1_digest(sha1_digest_), + no_announce(false) { } }; -struct ServerSoundParams -{ - float gain; - std::string to_player; - enum Type{ - SSP_LOCAL=0, - SSP_POSITIONAL=1, - SSP_OBJECT=2 - } type; - v3f pos; - u16 object; - float max_hear_distance; - bool loop; - - ServerSoundParams(): - gain(1.0), - to_player(""), - type(SSP_LOCAL), - pos(0,0,0), - object(0), - max_hear_distance(32*BS), - loop(false) - {} - - v3f getPos(ServerEnvironment *env, bool *pos_exists) const; -}; - +// Combines the pure sound (SimpleSoundSpec) with positional information struct ServerPlayingSound { - ServerSoundParams params; - std::set<u16> clients; // peer ids -}; - -class RemoteClient -{ -public: - // peer_id=0 means this client has no associated peer - // NOTE: If client is made allowed to exist while peer doesn't, - // this has to be set to 0 when there is no peer. - // Also, the client must be moved to some other container. - u16 peer_id; - // The serialization version to use with the client - u8 serialization_version; - // - u16 net_proto_version; - // Version is stored in here after INIT before INIT2 - u8 pending_serialization_version; - - bool definitions_sent; - - bool denied; - - RemoteClient(): - m_time_from_building(9999), - m_excess_gotblocks(0) - { - peer_id = 0; - serialization_version = SER_FMT_VER_INVALID; - net_proto_version = 0; - pending_serialization_version = SER_FMT_VER_INVALID; - definitions_sent = false; - denied = false; - m_nearest_unsent_d = 0; - m_nearest_unsent_reset_timer = 0.0; - m_nothing_to_send_counter = 0; - m_nothing_to_send_pause_timer = 0; - } - ~RemoteClient() - { - } - - /* - Finds block that should be sent next to the client. - Environment should be locked when this is called. - dtime is used for resetting send radius at slow interval - */ - void GetNextBlocks(Server *server, float dtime, - std::vector<PrioritySortedBlockTransfer> &dest); - - void GotBlock(v3s16 p); + SoundLocation type = SoundLocation::Local; - void SentBlock(v3s16 p); - - void SetBlockNotSent(v3s16 p); - void SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks); - - s32 SendingCount() - { - return m_blocks_sending.size(); - } - - // Increments timeouts and removes timed-out blocks from list - // NOTE: This doesn't fix the server-not-sending-block bug - // because it is related to emerging, not sending. - //void RunSendingTimeouts(float dtime, float timeout); - - void PrintInfo(std::ostream &o) - { - o<<"RemoteClient "<<peer_id<<": " - <<"m_blocks_sent.size()="<<m_blocks_sent.size() - <<", m_blocks_sending.size()="<<m_blocks_sending.size() - <<", m_nearest_unsent_d="<<m_nearest_unsent_d - <<", m_excess_gotblocks="<<m_excess_gotblocks - <<std::endl; - m_excess_gotblocks = 0; - } - - // Time from last placing or removing blocks - float m_time_from_building; - - /*JMutex m_dig_mutex; - float m_dig_time_remaining; - // -1 = not digging - s16 m_dig_tool_item; - v3s16 m_dig_position;*/ - - /* - List of active objects that the client knows of. - Value is dummy. - */ - std::set<u16> m_known_objects; + float gain = 1.0f; // for amplification of the base sound + float max_hear_distance = 32 * BS; + v3f pos; + u16 object = 0; + std::string to_player; + std::string exclude_player; -private: - /* - Blocks that have been sent to client. - - These don't have to be sent again. - - A block is cleared from here when client says it has - deleted it from it's memory + v3f getPos(ServerEnvironment *env, bool *pos_exists) const; - Key is position, value is dummy. - No MapBlock* is stored here because the blocks can get deleted. - */ - std::set<v3s16> m_blocks_sent; - s16 m_nearest_unsent_d; - v3s16 m_last_center; - float m_nearest_unsent_reset_timer; + SimpleSoundSpec spec; - /* - Blocks that are currently on the line. - This is used for throttling the sending of blocks. - - The size of this list is limited to some value - Block is added when it is sent with BLOCKDATA. - Block is removed when GOTBLOCKS is received. - Value is time from sending. (not used at the moment) - */ - std::map<v3s16, float> m_blocks_sending; + std::unordered_set<session_t> clients; // peer ids +}; - /* - Count of excess GotBlocks(). - There is an excess amount because the client sometimes - gets a block so late that the server sends it again, - and the client then sends two GOTBLOCKs. - This is resetted by PrintInfo() - */ - u32 m_excess_gotblocks; +struct MinimapMode { + MinimapType type = MINIMAP_TYPE_OFF; + std::string label; + u16 size = 0; + std::string texture; + u16 scale = 1; +}; - // CPU usage optimization - u32 m_nothing_to_send_counter; - float m_nothing_to_send_pause_timer; +// structure for everything getClientInfo returns, for convenience +struct ClientInfo { + ClientState state; + Address addr; + u32 uptime; + u8 ser_vers; + u16 prot_vers; + u8 major, minor, patch; + std::string vers_string, lang_code; }; class Server : public con::PeerHandler, public MapEventReceiver, - public InventoryManager, public IGameDef + public IGameDef { public: /* @@ -346,111 +145,123 @@ public: Server( const std::string &path_world, const SubgameSpec &gamespec, - bool simple_singleplayer_mode + bool simple_singleplayer_mode, + Address bind_addr, + bool dedicated, + ChatInterface *iface = nullptr, + std::string *on_shutdown_errmsg = nullptr ); ~Server(); - void start(unsigned short port); + DISABLE_CLASS_COPY(Server); + + void start(); void stop(); // This is mainly a way to pass the time to the server. // Actual processing is done in an another thread. void step(float dtime); // This is run by ServerThread and does the actual processing - void AsyncRunStep(); + void AsyncRunStep(bool initial_step=false); void Receive(); - void ProcessData(u8 *data, u32 datasize, u16 peer_id); + PlayerSAO* StageTwoClientInit(session_t peer_id); - // Environment must be locked when called + /* + * Command Handlers + */ + + void handleCommand(NetworkPacket* pkt); + + void handleCommand_Null(NetworkPacket* pkt) {}; + void handleCommand_Deprecated(NetworkPacket* pkt); + void handleCommand_Init(NetworkPacket* pkt); + void handleCommand_Init2(NetworkPacket* pkt); + void handleCommand_ModChannelJoin(NetworkPacket *pkt); + void handleCommand_ModChannelLeave(NetworkPacket *pkt); + void handleCommand_ModChannelMsg(NetworkPacket *pkt); + void handleCommand_RequestMedia(NetworkPacket* pkt); + void handleCommand_ClientReady(NetworkPacket* pkt); + void handleCommand_GotBlocks(NetworkPacket* pkt); + void handleCommand_PlayerPos(NetworkPacket* pkt); + void handleCommand_DeletedBlocks(NetworkPacket* pkt); + void handleCommand_InventoryAction(NetworkPacket* pkt); + void handleCommand_ChatMessage(NetworkPacket* pkt); + void handleCommand_Damage(NetworkPacket* pkt); + void handleCommand_PlayerItem(NetworkPacket* pkt); + void handleCommand_Respawn(NetworkPacket* pkt); + void handleCommand_Interact(NetworkPacket* pkt); + void handleCommand_RemovedSounds(NetworkPacket* pkt); + void handleCommand_NodeMetaFields(NetworkPacket* pkt); + void handleCommand_InventoryFields(NetworkPacket* pkt); + void handleCommand_FirstSrp(NetworkPacket* pkt); + void handleCommand_SrpBytesA(NetworkPacket* pkt); + void handleCommand_SrpBytesM(NetworkPacket* pkt); + void handleCommand_HaveMedia(NetworkPacket *pkt); + + void ProcessData(NetworkPacket *pkt); + + void Send(NetworkPacket *pkt); + void Send(session_t peer_id, NetworkPacket *pkt); + + // Helper for handleCommand_PlayerPos and handleCommand_Interact + void process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao, + NetworkPacket *pkt); + + // Both setter and getter need no envlock, + // can be called freely from threads void setTimeOfDay(u32 time); - bool getShutdownRequested() - { - return m_shutdown_requested; - } - /* Shall be called with the environment locked. This is accessed by the map, which is inside the environment, so it shouldn't be a problem. */ - void onMapEditEvent(MapEditEvent *event); - - /* - Shall be called with the environment and the connection locked. - */ - Inventory* getInventory(const InventoryLocation &loc); - void setInventoryModified(const InventoryLocation &loc); + void onMapEditEvent(const MapEditEvent &event); // Connection must be locked when called - std::wstring getStatusString(); + std::string getStatusString(); + inline double getUptime() const { return m_uptime_counter->get(); } - void requestShutdown(void) - { - m_shutdown_requested = true; - } + // read shutdown state + inline bool isShutdownRequested() const { return m_shutdown_state.is_requested; } + + // request server to shutdown + void requestShutdown(const std::string &msg, bool reconnect, float delay = 0.0f); // Returns -1 if failed, sound handle on success - // Envlock + conlock - s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams ¶ms); + // Envlock + s32 playSound(ServerPlayingSound ¶ms, bool ephemeral=false); void stopSound(s32 handle); + void fadeSound(s32 handle, float step, float gain); - // Envlock + conlock + // Envlock std::set<std::string> getPlayerEffectivePrivs(const std::string &name); bool checkPriv(const std::string &name, const std::string &priv); void reportPrivsModified(const std::string &name=""); // ""=all void reportInventoryFormspecModified(const std::string &name); + void reportFormspecPrependModified(const std::string &name); void setIpBanned(const std::string &ip, const std::string &name); void unsetIpBanned(const std::string &ip_or_name); std::string getBanDescription(const std::string &ip_or_name); - Address getPeerAddress(u16 peer_id) - { - return m_con.GetPeerAddress(peer_id); - } + void notifyPlayer(const char *name, const std::wstring &msg); + void notifyPlayers(const std::wstring &msg); - // Envlock and conlock should be locked when calling this - void notifyPlayer(const char *name, const std::wstring msg, const bool prepend); - void notifyPlayers(const std::wstring msg); - void spawnParticle(const char *playername, - v3f pos, v3f velocity, v3f acceleration, - float expirationtime, float size, - bool collisiondetection, std::string texture); - - void spawnParticleAll(v3f pos, v3f velocity, v3f acceleration, - float expirationtime, float size, - bool collisiondetection, std::string texture); - - u32 addParticleSpawner(const char *playername, - u16 amount, float spawntime, - v3f minpos, v3f maxpos, - v3f minvel, v3f maxvel, - v3f minacc, v3f maxacc, - float minexptime, float maxexptime, - float minsize, float maxsize, - bool collisiondetection, std::string texture); - - u32 addParticleSpawnerAll(u16 amount, float spawntime, - v3f minpos, v3f maxpos, - v3f minvel, v3f maxvel, - v3f minacc, v3f maxacc, - float minexptime, float maxexptime, - float minsize, float maxsize, - bool collisiondetection, std::string texture); - - void deleteParticleSpawner(const char *playername, u32 id); - void deleteParticleSpawnerAll(u32 id); - - // Creates or resets inventory - Inventory* createDetachedInventory(const std::string &name); + void spawnParticle(const std::string &playername, + const ParticleParameters &p); - // Envlock and conlock should be locked when using scriptapi - GameScripting *getScriptIface(){ return m_script; } + u32 addParticleSpawner(const ParticleSpawnerParameters &p, + ServerActiveObject *attached, const std::string &playername); + + void deleteParticleSpawner(const std::string &playername, u32 id); + + bool dynamicAddMedia(std::string filepath, u32 token, + const std::string &to_player, bool ephemeral); - // Envlock should be locked when using the rollback manager - IRollbackManager *getRollbackManager(){ return m_rollback; } + ServerInventoryManager *getInventoryMgr() const { return m_inventory_mgr.get(); } + void sendDetachedInventory(Inventory *inventory, const std::string &name, session_t peer_id); - //TODO: determine what (if anything) should be locked to access EmergeManager - EmergeManager *getEmergeManager(){ return m_emerge; } + // Envlock and conlock should be locked when using scriptapi + ServerScripting *getScriptIface(){ return m_script; } // actions: time-reversed list // Return value: success/failure @@ -460,89 +271,205 @@ public: // IGameDef interface // Under envlock virtual IItemDefManager* getItemDefManager(); - virtual INodeDefManager* getNodeDefManager(); + virtual const NodeDefManager* getNodeDefManager(); virtual ICraftDefManager* getCraftDefManager(); - virtual ITextureSource* getTextureSource(); - virtual IShaderSource* getShaderSource(); virtual u16 allocateUnknownNodeId(const std::string &name); - virtual ISoundManager* getSoundManager(); - virtual MtEventManager* getEventManager(); - virtual IRollbackReportSink* getRollbackReportSink(); + IRollbackManager *getRollbackManager() { return m_rollback; } + virtual EmergeManager *getEmergeManager() { return m_emerge; } + virtual ModMetadataDatabase *getModStorageDatabase() { return m_mod_storage_database; } IWritableItemDefManager* getWritableItemDefManager(); - IWritableNodeDefManager* getWritableNodeDefManager(); + NodeDefManager* getWritableNodeDefManager(); IWritableCraftDefManager* getWritableCraftDefManager(); - const ModSpec* getModSpec(const std::string &modname); - void getModNames(std::list<std::string> &modlist); - std::string getBuiltinLuaPath(); - - std::string getWorldPath(){ return m_path_world; } + virtual const std::vector<ModSpec> &getMods() const; + virtual const ModSpec* getModSpec(const std::string &modname) const; + static std::string getBuiltinLuaPath(); + virtual std::string getWorldPath() const { return m_path_world; } - bool isSingleplayer(){ return m_simple_singleplayer_mode; } + inline bool isSingleplayer() const + { return m_simple_singleplayer_mode; } - void setAsyncFatalError(const std::string &error) + inline void setAsyncFatalError(const std::string &error) + { m_async_fatal_error.set(error); } + inline void setAsyncFatalError(const LuaError &e) { - m_async_fatal_error.set(error); + setAsyncFatalError(std::string("Lua: ") + e.what()); } bool showFormspec(const char *name, const std::string &formspec, const std::string &formname); - - u32 hudAdd(Player *player, HudElement *element); - bool hudRemove(Player *player, u32 id); - bool hudChange(Player *player, u32 id, HudElementStat stat, void *value); - bool hudSetFlags(Player *player, u32 flags, u32 mask); - bool hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount); - void hudSetHotbarImage(Player *player, std::string name); - void hudSetHotbarSelectedImage(Player *player, std::string name); + Map & getMap() { return m_env->getMap(); } + ServerEnvironment & getEnv() { return *m_env; } + v3f findSpawnPos(); -private: + u32 hudAdd(RemotePlayer *player, HudElement *element); + bool hudRemove(RemotePlayer *player, u32 id); + bool hudChange(RemotePlayer *player, u32 id, HudElementStat stat, void *value); + bool hudSetFlags(RemotePlayer *player, u32 flags, u32 mask); + bool hudSetHotbarItemcount(RemotePlayer *player, s32 hotbar_itemcount); + void hudSetHotbarImage(RemotePlayer *player, const std::string &name); + void hudSetHotbarSelectedImage(RemotePlayer *player, const std::string &name); + + Address getPeerAddress(session_t peer_id); + + void setLocalPlayerAnimations(RemotePlayer *player, v2s32 animation_frames[4], + f32 frame_speed); + void setPlayerEyeOffset(RemotePlayer *player, const v3f &first, const v3f &third); + + void setSky(RemotePlayer *player, const SkyboxParams ¶ms); + void setSun(RemotePlayer *player, const SunParams ¶ms); + void setMoon(RemotePlayer *player, const MoonParams ¶ms); + void setStars(RemotePlayer *player, const StarParams ¶ms); - // con::PeerHandler implementation. - // These queue stuff to be processed by handlePeerChanges(). - // As of now, these create and remove clients and players. + void setClouds(RemotePlayer *player, const CloudParams ¶ms); + + void overrideDayNightRatio(RemotePlayer *player, bool do_override, float brightness); + + void setLighting(RemotePlayer *player, const Lighting &lighting); + + void RespawnPlayer(session_t peer_id); + + /* con::PeerHandler implementation. */ void peerAdded(con::Peer *peer); void deletingPeer(con::Peer *peer, bool timeout); - /* - Static send methods - */ + void DenySudoAccess(session_t peer_id); + void DenyAccess(session_t peer_id, AccessDeniedCode reason, + const std::string &custom_reason = "", bool reconnect = false); + void acceptAuth(session_t peer_id, bool forSudoMode); + void DisconnectPeer(session_t peer_id); + bool getClientConInfo(session_t peer_id, con::rtt_stat_type type, float *retval); + bool getClientInfo(session_t peer_id, ClientInfo &ret); - static void SendMovement(con::Connection &con, u16 peer_id); - static void SendHP(con::Connection &con, u16 peer_id, u8 hp); - static void SendBreath(con::Connection &con, u16 peer_id, u16 breath); - static void SendAccessDenied(con::Connection &con, u16 peer_id, - const std::wstring &reason); - static void SendDeathscreen(con::Connection &con, u16 peer_id, - bool set_camera_point_target, v3f camera_point_target); - static void SendItemDef(con::Connection &con, u16 peer_id, - IItemDefManager *itemdef, u16 protocol_version); - static void SendNodeDef(con::Connection &con, u16 peer_id, - INodeDefManager *nodedef, u16 protocol_version); + void printToConsoleOnly(const std::string &text); - /* - Non-static send methods. - Conlock should be always used. - Envlock usage is documented badly but it's easy to figure out - which ones access the environment. - */ + void HandlePlayerHPChange(PlayerSAO *sao, const PlayerHPChangeReason &reason); + void SendPlayerHP(PlayerSAO *sao, bool effect); + void SendPlayerBreath(PlayerSAO *sao); + void SendInventory(PlayerSAO *playerSAO, bool incremental); + void SendMovePlayer(session_t peer_id); + void SendPlayerSpeed(session_t peer_id, const v3f &added_vel); + void SendPlayerFov(session_t peer_id); - // Envlock and conlock should be locked when calling these - void SendInventory(u16 peer_id); - void SendChatMessage(u16 peer_id, const std::wstring &message); - void BroadcastChatMessage(const std::wstring &message); - void SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed); - void SendPlayerHP(u16 peer_id); - void SendPlayerBreath(u16 peer_id); - void SendMovePlayer(u16 peer_id); - void SendPlayerPrivileges(u16 peer_id); - void SendPlayerInventoryFormspec(u16 peer_id); - void SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname); - void SendHUDAdd(u16 peer_id, u32 id, HudElement *form); - void SendHUDRemove(u16 peer_id, u32 id); - void SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value); - void SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask); - void SendHUDSetParam(u16 peer_id, u16 param, const std::string &value); + void SendMinimapModes(session_t peer_id, + std::vector<MinimapMode> &modes, + size_t wanted_mode); + + void sendDetachedInventories(session_t peer_id, bool incremental); + + virtual bool registerModStorage(ModMetadata *storage); + virtual void unregisterModStorage(const std::string &name); + + bool joinModChannel(const std::string &channel); + bool leaveModChannel(const std::string &channel); + bool sendModChannelMessage(const std::string &channel, const std::string &message); + ModChannel *getModChannel(const std::string &channel); + + // Send block to specific player only + bool SendBlock(session_t peer_id, const v3s16 &blockpos); + + // Get or load translations for a language + Translations *getTranslationLanguage(const std::string &lang_code); + + static ModMetadataDatabase *openModStorageDatabase(const std::string &world_path); + + static ModMetadataDatabase *openModStorageDatabase(const std::string &backend, + const std::string &world_path, const Settings &world_mt); + + static bool migrateModStorageDatabase(const GameParams &game_params, + const Settings &cmd_args); + + // Lua files registered for init of async env, pair of modname + path + std::vector<std::pair<std::string, std::string>> m_async_init_files; + + // Data transferred into async envs at init time + std::unique_ptr<PackedValue> m_async_globals_data; + + // Bind address + Address m_bind_addr; + + // Environment mutex (envlock) + std::mutex m_env_mutex; + +private: + friend class EmergeThread; + friend class RemoteClient; + friend class TestServerShutdownState; + + struct ShutdownState { + friend class TestServerShutdownState; + public: + bool is_requested = false; + bool should_reconnect = false; + std::string message; + + void reset(); + void trigger(float delay, const std::string &msg, bool reconnect); + void tick(float dtime, Server *server); + std::wstring getShutdownTimerMessage() const; + bool isTimerRunning() const { return m_timer > 0.0f; } + private: + float m_timer = 0.0f; + }; + + struct PendingDynamicMediaCallback { + std::string filename; // only set if media entry and file is to be deleted + float expiry_timer; + std::unordered_set<session_t> waiting_players; + }; + + // The standard library does not implement std::hash for pairs so we have this: + struct SBCHash { + size_t operator() (const std::pair<v3s16, u16> &p) const { + return std::hash<v3s16>()(p.first) ^ p.second; + } + }; + + typedef std::unordered_map<std::pair<v3s16, u16>, std::string, SBCHash> SerializedBlockCache; + + void init(); + + void SendMovement(session_t peer_id); + void SendHP(session_t peer_id, u16 hp, bool effect); + void SendBreath(session_t peer_id, u16 breath); + void SendAccessDenied(session_t peer_id, AccessDeniedCode reason, + const std::string &custom_reason, bool reconnect = false); + void SendAccessDenied_Legacy(session_t peer_id, const std::wstring &reason); + void SendDeathscreen(session_t peer_id, bool set_camera_point_target, + v3f camera_point_target); + void SendItemDef(session_t peer_id, IItemDefManager *itemdef, u16 protocol_version); + void SendNodeDef(session_t peer_id, const NodeDefManager *nodedef, + u16 protocol_version); + + /* mark blocks not sent for all clients */ + void SetBlocksNotSent(std::map<v3s16, MapBlock *>& block); + + + virtual void SendChatMessage(session_t peer_id, const ChatMessage &message); + void SendTimeOfDay(session_t peer_id, u16 time, f32 time_speed); + + void SendLocalPlayerAnimations(session_t peer_id, v2s32 animation_frames[4], + f32 animation_speed); + void SendEyeOffset(session_t peer_id, v3f first, v3f third); + void SendPlayerPrivileges(session_t peer_id); + void SendPlayerInventoryFormspec(session_t peer_id); + void SendPlayerFormspecPrepend(session_t peer_id); + void SendShowFormspecMessage(session_t peer_id, const std::string &formspec, + const std::string &formname); + void SendHUDAdd(session_t peer_id, u32 id, HudElement *form); + void SendHUDRemove(session_t peer_id, u32 id); + void SendHUDChange(session_t peer_id, u32 id, HudElementStat stat, void *value); + void SendHUDSetFlags(session_t peer_id, u32 flags, u32 mask); + void SendHUDSetParam(session_t peer_id, u16 param, const std::string &value); + void SendSetSky(session_t peer_id, const SkyboxParams ¶ms); + void SendSetSun(session_t peer_id, const SunParams ¶ms); + void SendSetMoon(session_t peer_id, const MoonParams ¶ms); + void SendSetStars(session_t peer_id, const StarParams ¶ms); + void SendCloudParams(session_t peer_id, const CloudParams ¶ms); + void SendOverrideDayNightRatio(session_t peer_id, bool do_override, float ratio); + void SendSetLighting(session_t peer_id, const Lighting &lighting); + void broadcastModChannelMessage(const std::string &channel, + const std::string &message, session_t from_peer); /* Send a node removal/addition event to all clients except ignore_id. @@ -550,86 +477,69 @@ private: far_d_nodes are ignored and their peer_ids are added to far_players */ // Envlock and conlock should be locked when calling these - void sendRemoveNode(v3s16 p, u16 ignore_id=0, - std::list<u16> *far_players=NULL, float far_d_nodes=100); - void sendAddNode(v3s16 p, MapNode n, u16 ignore_id=0, - std::list<u16> *far_players=NULL, float far_d_nodes=100); - void setBlockNotSent(v3s16 p); + void sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players = nullptr, + float far_d_nodes = 100); + void sendAddNode(v3s16 p, MapNode n, + std::unordered_set<u16> *far_players = nullptr, + float far_d_nodes = 100, bool remove_metadata = true); + + void sendMetadataChanged(const std::unordered_set<v3s16> &positions, + float far_d_nodes = 100); // Environment and Connection must be locked when called - void SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version); + // `cache` may only be very short lived! (invalidation not handeled) + void SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver, + u16 net_proto_version, SerializedBlockCache *cache = nullptr); // Sends blocks to clients (locks env and con on its own) void SendBlocks(float dtime); + bool addMediaFile(const std::string &filename, const std::string &filepath, + std::string *filedata = nullptr, std::string *digest = nullptr); void fillMediaCache(); - void sendMediaAnnouncement(u16 peer_id); - void sendRequestedMedia(u16 peer_id, - const std::list<MediaRequest> &tosend); - - void sendDetachedInventory(const std::string &name, u16 peer_id); - void sendDetachedInventoryToAll(const std::string &name); - void sendDetachedInventories(u16 peer_id); - - // Adds a ParticleSpawner on peer with peer_id - void SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, - v3f minpos, v3f maxpos, - v3f minvel, v3f maxvel, - v3f minacc, v3f maxacc, - float minexptime, float maxexptime, - float minsize, float maxsize, - bool collisiondetection, std::string texture, u32 id); - - // Adds a ParticleSpawner on all peers - void SendAddParticleSpawnerAll(u16 amount, float spawntime, - v3f minpos, v3f maxpos, - v3f minvel, v3f maxvel, - v3f minacc, v3f maxacc, - float minexptime, float maxexptime, - float minsize, float maxsize, - bool collisiondetection, std::string texture, u32 id); - - // Deletes ParticleSpawner on a single client - void SendDeleteParticleSpawner(u16 peer_id, u32 id); - - // Deletes ParticleSpawner on all clients - void SendDeleteParticleSpawnerAll(u32 id); - - // Spawns particle on single client - void SendSpawnParticle(u16 peer_id, - v3f pos, v3f velocity, v3f acceleration, - float expirationtime, float size, - bool collisiondetection, std::string texture); - - // Spawns particle on all clients - void SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration, - float expirationtime, float size, - bool collisiondetection, std::string texture); + void sendMediaAnnouncement(session_t peer_id, const std::string &lang_code); + void sendRequestedMedia(session_t peer_id, + const std::vector<std::string> &tosend); + void stepPendingDynMediaCallbacks(float dtime); + + // Adds a ParticleSpawner on peer with peer_id (PEER_ID_INEXISTENT == all) + void SendAddParticleSpawner(session_t peer_id, u16 protocol_version, + const ParticleSpawnerParameters &p, u16 attached_id, u32 id); + + void SendDeleteParticleSpawner(session_t peer_id, u32 id); + + // Spawns particle on peer with peer_id (PEER_ID_INEXISTENT == all) + void SendSpawnParticle(session_t peer_id, u16 protocol_version, + const ParticleParameters &p); + + void SendActiveObjectRemoveAdd(RemoteClient *client, PlayerSAO *playersao); + void SendActiveObjectMessages(session_t peer_id, const std::string &datas, + bool reliable = true); + void SendCSMRestrictionFlags(session_t peer_id); /* Something random */ - void DiePlayer(u16 peer_id); - void RespawnPlayer(u16 peer_id); - void DenyAccess(u16 peer_id, const std::wstring &reason); + void HandlePlayerDeath(PlayerSAO* sao, const PlayerHPChangeReason &reason); + void DeleteClient(session_t peer_id, ClientDeletionReason reason); + void UpdateCrafting(RemotePlayer *player); + bool checkInteractDistance(RemotePlayer *player, const f32 d, const std::string &what); - enum ClientDeletionReason { - CDR_LEAVE, - CDR_TIMEOUT, - CDR_DENY - }; - void DeleteClient(u16 peer_id, ClientDeletionReason reason); + void handleChatInterfaceEvent(ChatEvent *evt); - void UpdateCrafting(u16 peer_id); + // This returns the answer to the sender of wmessage, or "" if there is none + std::wstring handleChat(const std::string &name, std::wstring wmessage_input, + bool check_shout_priv = false, RemotePlayer *player = nullptr); + void handleAdminChat(const ChatEventChat *evt); // When called, connection mutex should be locked - RemoteClient* getClient(u16 peer_id); - RemoteClient* getClientNoEx(u16 peer_id); + RemoteClient* getClient(session_t peer_id, ClientState state_min = CS_Active); + RemoteClient* getClientNoEx(session_t peer_id, ClientState state_min = CS_Active); // When called, environment mutex should be locked - std::string getPlayerName(u16 peer_id); - PlayerSAO* getPlayerSAO(u16 peer_id); + std::string getPlayerName(session_t peer_id); + PlayerSAO *getPlayerSAO(session_t peer_id); /* Get a player from memory or creates one. @@ -638,17 +548,13 @@ private: Call with env and con locked. */ - PlayerSAO *emergePlayer(const char *name, u16 peer_id); + PlayerSAO *emergePlayer(const char *name, session_t peer_id, u16 proto_version); - // Locks environment and connection by its own - struct PeerChange; - void handlePeerChange(PeerChange &c); void handlePeerChanges(); /* Variables */ - // World directory std::string m_path_world; // Subgame specification @@ -656,111 +562,102 @@ private: // If true, do not allow multiple players and hide some multiplayer // functionality bool m_simple_singleplayer_mode; + u16 m_max_chatmessage_length; + // For "dedicated" server list flag + bool m_dedicated; + Settings *m_game_settings = nullptr; // Thread can set; step() will throw as ServerError MutexedVariable<std::string> m_async_fatal_error; // Some timers - float m_liquid_transform_timer; - float m_liquid_transform_every; - float m_print_info_timer; - float m_masterserver_timer; - float m_objectdata_timer; - float m_emergethread_trigger_timer; - float m_savemap_timer; + float m_liquid_transform_timer = 0.0f; + float m_liquid_transform_every = 1.0f; + float m_masterserver_timer = 0.0f; + float m_emergethread_trigger_timer = 0.0f; + float m_savemap_timer = 0.0f; IntervalLimiter m_map_timer_and_unload_interval; - // NOTE: If connection and environment are both to be locked, - // environment shall be locked first. - // Environment - ServerEnvironment *m_env; - JMutex m_env_mutex; + ServerEnvironment *m_env = nullptr; + + // Reference to the server map until ServerEnvironment is initialized + // after that this variable must be a nullptr + ServerMap *m_startup_server_map = nullptr; - // Connection - con::Connection m_con; - JMutex m_con_mutex; - // Connected clients (behind the con mutex) - std::map<u16, RemoteClient*> m_clients; - u16 m_clients_number; //for announcing masterserver + // server connection + std::shared_ptr<con::Connection> m_con; // Ban checking - BanManager *m_banmanager; + BanManager *m_banmanager = nullptr; // Rollback manager (behind m_env_mutex) - IRollbackManager *m_rollback; - bool m_rollback_sink_enabled; - bool m_enable_rollback_recording; // Updated once in a while + IRollbackManager *m_rollback = nullptr; // Emerge manager - EmergeManager *m_emerge; + EmergeManager *m_emerge = nullptr; // Scripting // Envlock and conlock should be locked when using Lua - GameScripting *m_script; + ServerScripting *m_script = nullptr; // Item definition manager IWritableItemDefManager *m_itemdef; // Node definition manager - IWritableNodeDefManager *m_nodedef; + NodeDefManager *m_nodedef; // Craft definition manager IWritableCraftDefManager *m_craftdef; - // Event manager - EventManager *m_event; - // Mods - std::vector<ModSpec> m_mods; + std::unique_ptr<ServerModManager> m_modmgr; + + std::unordered_map<std::string, Translations> server_translations; /* Threads */ - // A buffer for time steps // step() increments and AsyncRunStep() run by m_thread reads it. - float m_step_dtime; - JMutex m_step_dtime_mutex; + float m_step_dtime = 0.0f; + std::mutex m_step_dtime_mutex; // The server mainly operates in this thread - ServerThread *m_thread; + ServerThread *m_thread = nullptr; /* Time related stuff */ - // Timer for sending time of day over network - float m_time_of_day_send_timer; - // Uptime of server in seconds - MutexedVariable<double> m_uptime; + float m_time_of_day_send_timer = 0.0f; + + /* + Client interface + */ + ClientInterface m_clients; /* Peer change queue. Queues stuff from peerAdded() and deletingPeer() to handlePeerChanges() */ - enum PeerChangeType - { - PEER_ADDED, - PEER_REMOVED - }; - struct PeerChange - { - PeerChangeType type; - u16 peer_id; - bool timeout; - }; - Queue<PeerChange> m_peer_change_queue; + std::queue<con::PeerChange> m_peer_change_queue; + + std::unordered_map<session_t, std::string> m_formspec_state_data; /* Random stuff */ - // Mod parent directory paths - std::list<std::string> m_modspaths; + ShutdownState m_shutdown_state; - bool m_shutdown_requested; + ChatInterface *m_admin_chat; + std::string m_admin_nick; + + // if a mod-error occurs in the on_shutdown callback, the error message will + // be written into this + std::string *const m_on_shutdown_errmsg; /* Map edit event queue. Automatically receives all map edits. @@ -775,13 +672,7 @@ private: Queue of map edits from the environment for sending to the clients This is behind m_env_mutex */ - Queue<MapEditEvent*> m_unsent_map_edit_queue; - /* - Set to true when the server itself is modifying the map and does - all sending of information by itself. - This is behind m_env_mutex - */ - bool m_ignore_map_edit_events; + std::queue<MapEditEvent*> m_unsent_map_edit_queue; /* If a non-empty area, map edit events contained within are left unsent. Done at map generation time to speed up editing of the @@ -789,42 +680,52 @@ private: This is behind m_env_mutex */ VoxelArea m_ignore_map_edit_events_area; - /* - If set to !=0, the incoming MapEditEvents are modified to have - this peed id as the disabled recipient - This is behind m_env_mutex - */ - u16 m_ignore_map_edit_events_peer_id; - friend class EmergeThread; - friend class RemoteClient; + // media files known to server + std::unordered_map<std::string, MediaInfo> m_media; - std::map<std::string,MediaInfo> m_media; + // pending dynamic media callbacks, clients inform the server when they have a file fetched + std::unordered_map<u32, PendingDynamicMediaCallback> m_pending_dyn_media; + float m_step_pending_dyn_media_timer = 0.0f; /* Sounds */ - std::map<s32, ServerPlayingSound> m_playing_sounds; - s32 m_next_sound_id; - - /* - Detached inventories (behind m_env_mutex) - */ - // key = name - std::map<std::string, Inventory*> m_detached_inventories; - - /* - Particles - */ - std::vector<u32> m_particlespawner_ids; + std::unordered_map<s32, ServerPlayingSound> m_playing_sounds; + s32 m_next_sound_id = 0; // positive values only + s32 nextSoundId(); + + std::unordered_map<std::string, ModMetadata *> m_mod_storages; + ModMetadataDatabase *m_mod_storage_database = nullptr; + float m_mod_storage_save_timer = 10.0f; + + // CSM restrictions byteflag + u64 m_csm_restriction_flags = CSMRestrictionFlags::CSM_RF_NONE; + u32 m_csm_restriction_noderange = 8; + + // ModChannel manager + std::unique_ptr<ModChannelMgr> m_modchannel_mgr; + + // Inventory manager + std::unique_ptr<ServerInventoryManager> m_inventory_mgr; + + // Global server metrics backend + std::unique_ptr<MetricsBackend> m_metrics_backend; + + // Server metrics + MetricCounterPtr m_uptime_counter; + MetricGaugePtr m_player_gauge; + MetricGaugePtr m_timeofday_gauge; + MetricGaugePtr m_lag_gauge; + MetricCounterPtr m_aom_buffer_counter[2]; // [0] = rel, [1] = unrel + MetricCounterPtr m_packet_recv_counter; + MetricCounterPtr m_packet_recv_processed_counter; + MetricCounterPtr m_map_edit_event_counter; }; /* Runs a simple dedicated server loop. - Shuts down when run is set to false. + Shuts down when kill is set to true. */ -void dedicated_server_loop(Server &server, bool &run); - -#endif - +void dedicated_server_loop(Server &server, bool &kill); |