#ifndef STAR_UNIVERSE_SERVER_HPP #define STAR_UNIVERSE_SERVER_HPP #include "StarLockFile.hpp" #include "StarIdMap.hpp" #include "StarWorkerPool.hpp" #include "StarGameTypes.hpp" #include "StarCelestialCoordinate.hpp" #include "StarServerClientContext.hpp" #include "StarWorldServerThread.hpp" #include "StarSystemWorldServerThread.hpp" #include "StarUniverseConnection.hpp" #include "StarUniverseSettings.hpp" namespace Star { STAR_CLASS(Clock); STAR_CLASS(File); STAR_CLASS(Player); STAR_CLASS(ChatProcessor); STAR_CLASS(CommandProcessor); STAR_CLASS(TeamManager); STAR_CLASS(UniverseServer); STAR_CLASS(WorldTemplate); STAR_CLASS(WorldServer); STAR_CLASS(UniverseSettings); STAR_EXCEPTION(UniverseServerException, StarException); // Manages all running worlds, listens for new client connections and marshalls // between all the different worlds and all the different client connections // and routes packets between them. class UniverseServer : public Thread { public: UniverseServer(String const& storageDir); ~UniverseServer(); // If enabled, will listen on the configured server port for incoming // connections. void setListeningTcp(bool listenTcp); // Connects an arbitrary UniverseConnection to this server void addClient(UniverseConnection remoteConnection); // Constructs an in-process connection to a UniverseServer for a // UniverseClient, and returns the other side of the connection. UniverseConnection addLocalClient(); // Signals the UniverseServer to stop and then joins the thread. void stop(); void setPause(bool pause); List activeWorlds() const; bool isWorldActive(WorldId const& worldId) const; List clientIds() const; size_t numberOfClients() const; uint32_t maxClients() const; bool isConnectedClient(ConnectionId clientId) const; String clientDescriptor(ConnectionId clientId) const; String clientNick(ConnectionId clientId) const; Maybe findNick(String const& nick) const; Maybe uuidForClient(ConnectionId clientId) const; Maybe clientForUuid(Uuid const& uuid) const; void adminBroadcast(String const& text); void adminWhisper(ConnectionId clientId, String const& text); String adminCommand(String text); bool isAdmin(ConnectionId clientId) const; bool canBecomeAdmin(ConnectionId clientId) const; void setAdmin(ConnectionId clientId, bool admin); bool isLocal(ConnectionId clientId) const; bool isPvp(ConnectionId clientId) const; void setPvp(ConnectionId clientId, bool pvp); RpcThreadPromise sendWorldMessage(WorldId const& worldId, String const& message, JsonArray const& args = {}); void clientWarpPlayer(ConnectionId clientId, WarpAction action, bool deploy = false); void clientFlyShip(ConnectionId clientId, Vec3I const& system, SystemLocation const& location); WorldId clientWorld(ConnectionId clientId) const; CelestialCoordinate clientShipCoordinate(ConnectionId clientId) const; ClockPtr universeClock() const; UniverseSettingsPtr universeSettings() const; CelestialDatabase& celestialDatabase(); // If the client exists and is in a valid connection state, executes the // given function on the client world and player object in a thread safe way. // Returns true if function was called, false if client was not found or in // an invalid connection state. bool executeForClient(ConnectionId clientId, function action); void disconnectClient(ConnectionId clientId, String const& reason); void banUser(ConnectionId clientId, String const& reason, pair banType, Maybe timeout); bool unbanIp(String const& addressString); bool unbanUuid(String const& uuidString); bool updatePlanetType(CelestialCoordinate const& coordinate, String const& newType, String const& weatherBiome); protected: virtual void run(); private: struct TimeoutBan { int64_t banExpiry; String reason; Maybe ip; Maybe uuid; }; void processUniverseFlags(); void sendPendingChat(); void updateTeams(); void updateShips(); void sendClockUpdates(); void sendClientContextUpdate(ServerClientContextPtr clientContext); void sendClientContextUpdates(); void kickErroredPlayers(); void reapConnections(); void processPlanetTypeChanges(); void warpPlayers(); void flyShips(); void arriveShips(); void respondToCelestialRequests(); void processChat(); void clearBrokenWorlds(); void handleWorldMessages(); void shutdownInactiveWorlds(); void doTriggeredStorage(); void saveSettings(); void loadSettings(); // Either returns the default configured starter world, or a new randomized // starter world, or if a randomized world is not yet available, starts a job // to find a randomized starter world and returns nothing until it is ready. Maybe nextStarterWorld(); void loadTempWorldIndex(); void saveTempWorldIndex(); String tempWorldFile(InstanceWorldId const& worldId) const; Maybe isBannedUser(Maybe hostAddress, Uuid playerUuid) const; void doTempBan(ConnectionId clientId, String const& reason, pair banType, int timeout); void doPermBan(ConnectionId clientId, String const& reason, pair banType); void removeTimedBan(); void addCelestialRequests(ConnectionId clientId, List requests); void worldUpdated(WorldServerThread* worldServer); void systemWorldUpdated(SystemWorldServerThread* systemWorldServer); void packetsReceived(UniverseConnectionServer* connectionServer, ConnectionId clientId, List packets); void acceptConnection(UniverseConnection connection, Maybe remoteAddress); // Main lock and clients read lock must be held when calling WarpToWorld resolveWarpAction(WarpAction warpAction, ConnectionId clientId, bool deploy) const; // Main lock and clients write lock must be held when calling void doDisconnection(ConnectionId clientId, String const& reason); // Clients read lock must be held when calling Maybe getClientForUuid(Uuid const& uuid) const; // Get the world only if it is already loaded, Main lock must be held when // calling. WorldServerThreadPtr getWorld(WorldId const& worldId); // If the world is not created, block and load it, otherwise just return the // loaded world. Main lock and Clients read lock must be held when calling. WorldServerThreadPtr createWorld(WorldId const& worldId); // Trigger off-thread world creation, returns a value when the creation is // finished, either successfully or with an error. Main lock and Clients // read lock must be held when calling. Maybe triggerWorldCreation(WorldId const& worldId); // Main lock and clients read lock must be held when calling world promise // generators Maybe> makeWorldPromise(WorldId const& worldId); Maybe> shipWorldPromise(ClientShipWorldId const& uuid); Maybe> celestialWorldPromise(CelestialWorldId const& coordinate); Maybe> instanceWorldPromise(InstanceWorldId const& instanceWorld); // If the system world is not created, initialize it, otherwise return the // already initialized one SystemWorldServerThreadPtr createSystemWorld(Vec3I const& location); bool instanceWorldStoredOrActive(InstanceWorldId const& worldId) const; // Signal that a world either failed to load, or died due to an exception, // kicks clients if that world is a ship world. Main lock and clients read // lock must be held when calling. void worldDiedWithError(WorldId world); // Get SkyParameters if the coordinate is a valid world, and empty // SkyParameters otherwise. SkyParameters celestialSkyParameters(CelestialCoordinate const& coordinate) const; mutable RecursiveMutex m_mainLock; String m_storageDirectory; ByteArray m_assetsDigest; Maybe m_storageDirectoryLock; StringMap m_speciesShips; CelestialMasterDatabasePtr m_celestialDatabase; ClockPtr m_universeClock; UniverseSettingsPtr m_universeSettings; WorkerPool m_workerPool; int64_t m_storageTriggerDeadline; int64_t m_clearBrokenWorldsDeadline; int64_t m_lastClockUpdateSent; atomic m_stop; atomic m_listenTcp; mutable ReadersWriterMutex m_clientsLock; unsigned m_maxPlayers; IdMap m_clients; shared_ptr> m_pause; Map>> m_worlds; Map> m_tempWorldIndex; Map m_systemWorlds; UniverseConnectionServerPtr m_connectionServer; List> m_connectionAcceptThreads; LinkedList> m_deadConnections; ChatProcessorPtr m_chatProcessor; CommandProcessorPtr m_commandProcessor; TeamManagerPtr m_teamManager; HashMap> m_pendingPlayerWarps; HashMap, Maybe>> m_queuedFlights; HashMap> m_pendingFlights; HashMap m_pendingArrivals; HashMap m_pendingDisconnections; HashMap>> m_pendingCelestialRequests; List> m_pendingFlagActions; HashMap>> m_pendingChat; Maybe> m_nextRandomizedStarterWorld; Map> m_pendingWorldMessages; List m_tempBans; }; } #endif