#pragma once #include #include #include #include #include "content/ContentPack.hpp" #include "interfaces/Serializable.hpp" #include "typedefs.hpp" #include "util/timeutil.hpp" class Content; class WorldFiles; class Level; class ContentReport; struct EngineSettings; namespace fs = std::filesystem; class world_load_error : public std::runtime_error { public: world_load_error(const std::string& message); }; struct WorldInfo : public Serializable { std::string name; std::string generator; uint64_t seed; int64_t nextInventoryId = 1; int64_t nextPlayerId = 0; /// @brief Day/night loop timer in range 0..1 where /// 0.0 - is midnight and /// 0.5 - is noon float daytime = timeutil::time_value(10, 00, 00); // looking bad float daytimeSpeed = 1.0f; /// @brief total time passed in the world (not depending on daytimeSpeed) double totalTime = 0.0; /// @brief will be replaced with weather in future float fog = 0.0f; entityid_t nextEntityId = 0; int major = 0, minor = -1; dv::value serialize() const override; void deserialize(const dv::value& src) override; }; /// @brief holds all world data except the level (chunks and objects) class World { WorldInfo info {}; const Content& content; std::vector packs; void writeResources(const Content& content); public: std::shared_ptr wfile; World( WorldInfo info, const std::shared_ptr& worldFiles, const Content& content, const std::vector& packs ); ~World(); /// @brief Update world day-time and total time /// @param delta delta-time void updateTimers(float delta); /// @brief Write all unsaved level data to the world directory void write(Level* level); /// @brief Check world indices and generate ContentReport if convert required /// @param directory world directory /// @param content current Content instance /// @return ContentReport if world convert required else nullptr static std::shared_ptr checkIndices( const std::shared_ptr& worldFiles, const Content* content ); /// @brief Create new world /// @param name internal world name /// @param directory root world directory /// @param type of the world /// @param seed world generation seed /// @param settings current engine settings /// @param content current engine Content instance /// with all world content-packs applied /// @param packs vector of all world content-packs /// @return Level instance containing World instance static std::unique_ptr create( const std::string& name, const std::string& generator, const fs::path& directory, uint64_t seed, EngineSettings& settings, const Content& content, const std::vector& packs ); /// @brief Load an existing world /// @param worldFiles world files manager /// @param settings current engine settings /// @param content current engine Content instance /// with all world content-packs applied /// @param packs vector of all world content-packs /// @return Level instance containing World instance /// @throws world_load_error on world.json load error static std::unique_ptr load( const std::shared_ptr& worldFiles, EngineSettings& settings, const Content& content, const std::vector& packs ); void setName(const std::string& name); void setSeed(uint64_t seed); void setGenerator(const std::string& generator); /// @brief Check if world has content-pack installed /// @param id content-pack id bool hasPack(const std::string& id) const; /// @brief Get internal world name (not the folder name) /// @return name stored in world.json std::string getName() const; /// @brief Get world generation seed uint64_t getSeed() const; /// @brief Get world generator id std::string getGenerator() const; bool isNameless() const { return info.name.empty(); } WorldInfo& getInfo() { return info; } const WorldInfo& getInfo() const { return info; } /// @brief Get vector of all content-packs installed in world const std::vector& getPacks() const; /// @brief Get next inventory id and increment it's counter /// @return integer >= 1 int64_t getNextInventoryId() { return info.nextInventoryId++; } };