diff --git a/Deer/Include/DeerCore/DataManagment.h b/Deer/Include/DeerCore/DataManagment.h deleted file mode 100644 index a0460b8..0000000 --- a/Deer/Include/DeerCore/DataManagment.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once -#include "DeerCore/Tools/Memory.h" -#include "DeerCore/Tools/TypeDefs.h" - -#include -#include -#include - -namespace Deer { - /* - class DataSource { - public: - using DataImporter = [ClassOfTheDataImporter] - }; - */ - using StorageMetadata = std::unordered_map; - template - concept HasMetadata = requires(const std::string& location) { - { T::loadMetadata(location) } -> std::same_as; - { T::saveMetadata(StorageMetadata{}, location) }; - }; - - class StorageData { - public: - StorageData() = default; - StorageData(uint32_t dataSize) : size(dataSize), data(MakeScope(dataSize)) {} - - inline uint8_t* getData() { return data.get(); } - inline const uint8_t* getData() const { return data.get(); } - inline uint32_t getSize() const { return size; } - inline StorageMetadata& getMetadata() { return metadata; } - - template - Scope deserialize(); - - template - static StorageData serialize(const T&); - - inline explicit operator bool() const { return size != 0; } - - private: - StorageMetadata metadata; - Scope data = nullptr; - uint32_t size = 0; - }; - - template - class StorageBackend { - public: - static StorageData loadData(const std::string& location); - static void saveData(const std::string& location, const StorageData& data); - - static StorageMetadata loadMetadata(const std::string& location); - static void saveMetadata(const StorageMetadata& metadata, const std::string& location); - - static std::vector indexResources(const std::string& location); - }; - - template - class DataManager { - public: - template - static Scope load(const std::string& dataId) { - StorageData data = StorageBackend::loadData(dataId); - - if constexpr (HasMetadata>) { - data.getMetadata() = StorageBackend::loadMetadata(dataId); - data.getMetadata()["dataId"] = dataId; - } - - return data.deserialize(); - } - - template - static void store(const std::string& dataId, T& value) { - StorageData data = StorageData::serialize(value); - StorageBackend::saveData(dataId, data); - if constexpr (HasMetadata>) { - StorageBackend::saveMetadata(data.getMetadata(), dataId); - } - } - }; -} // namespace Deer \ No newline at end of file diff --git a/Deer/Include/DeerCore/DataStore.h b/Deer/Include/DeerCore/DataStore.h deleted file mode 100755 index 7db6fdf..0000000 --- a/Deer/Include/DeerCore/DataStore.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once -#include -#include -#include - -#include "DeerCore/Tools/Path.h" - -#define DEER_RESOURCE_PATH "Assets" - -#define DEER_VOXEL_PATH "Voxels" -#define DEER_VOXEL_DATA_PATH "Voxels/Data" -#define DEER_VOXEL_ASPECT_PATH "Voxels/Visuals" -#define DEER_VOXEL_TEXTURE_PATH "Voxels/Textures" -#define DEER_VOXEL_SHADER_PATH "Voxels/Shaders" - -#define DEER_EDITOR_PATH "Editor" -#define DEER_EDITOR_PANEL_PATH "Editor/Panels" -#define DEER_EDITOR_SERVICE_PATH "Editor/Services" - -#define DEER_MESH_EXTENSION ".dmesh" -#define DEER_SHADER_EXTENSION ".glsl" -#define DEER_SCRIPT_EXTENSION ".as" - -#define DEER_BIN_PATH "bin" -#define DEER_TEMP_PATH "tmp" -#define DEER_NULL_PATH "null" - -namespace Deer { - - struct DirectoryData { - std::vector dirs; - std::vector elements; - }; - - // Namespace to manage memory interactions - namespace DataStore { - // Clears the cache of dir data - void clearCache(); - - // Rerturns a directory data with the elements relative to the id - const DirectoryData& getDirData(const Path& id, const Path& dir, const char* extension); - - // TODO: Add safety - // Returns the data of the specified file path - bool loadFileData(const Path& id, const Path& name, uint8_t** data, uint32_t* size); - // Returns the data of the specified file path avoiding extension - bool loadGlobalFileData(const Path& id, const Path& name, uint8_t** data, uint32_t* size); - void freeFileData(uint8_t*); - - void createFolder(const Path& path); - - void saveFile(const Path&, uint8_t* data, uint32_t size); - uint8_t* readFile(const Path&, uint32_t* size); - void deleteFile(const Path&); - - // Refactor---- - void compressFiles(std::vector files, const Path& path); - std::vector getFiles(const Path& path, - const std::string& extension); - // Refactor---- - } // namespace DataStore -} // namespace Deer \ No newline at end of file diff --git a/Deer/Include/DeerCore/EntityEnviroment.h b/Deer/Include/DeerCore/EntityEnviroment.h index c6b2033..a124a15 100755 --- a/Deer/Include/DeerCore/EntityEnviroment.h +++ b/Deer/Include/DeerCore/EntityEnviroment.h @@ -1,7 +1,6 @@ #pragma once #include "DeerCore/Components.h" #include "DeerCore/Log.h" -#include "DeerCore/Resource.h" #include "DeerCore/Tools/Memory.h" #include "entt/entt.hpp" diff --git a/Deer/Include/DeerCore/Resource.h b/Deer/Include/DeerCore/Resource.h deleted file mode 100644 index 9f77717..0000000 --- a/Deer/Include/DeerCore/Resource.h +++ /dev/null @@ -1,140 +0,0 @@ -#pragma once -#include "DeerCore/DataManagment.h" -#include "DeerCore/Log.h" -#include "DeerCore/Tools/Memory.h" -#include "DeerCore/Tools/Path.h" -#include "DeerCore/Tools/TypeDefs.h" - -#include -#include -#include - -namespace Deer { - template - class ResourceManager; - - template - class Resource { - public: - int32_t getResourceId() const { return resourceId; } - - bool isValid() const { return ResourceManager::isValid(*this); } - T& getData() { return ResourceManager::getResourceData(*this); } - - const std::string& getStorageId() const { return ResourceManager::getStorageId(*this); } - - inline explicit operator bool() const { return resourceId >= 0; } - - static Resource unsafeFromId(int32_t id) { - Resource res; - res.resourceId = id; - return res; - } - - private: - // -1 = no resource loaded - int32_t resourceId = -1; - friend ResourceManager; - }; - - template - class ResourceBuilder { - public: - using BaseDataType = char; - static Scope buildResource(const BaseDataType& baseData) { - static_assert(sizeof(T) == 0, "ResourceBuilder must be specialized for this type T"); - return nullptr; - } - }; - - template - class ResourceManager { - private: - struct ResourceData { - public: - ResourceData(const std::string& _resourceId, Scope&& _data) - : storageId(_resourceId), data(std::move(_data)) {} - - Scope data; - const std::string storageId; - }; - - static std::vector resources; - static std::unordered_map> resourceCache; - - public: - template - static Resource loadResource(const std::string& storageId) { - if (resourceCache.contains(storageId)) - return resourceCache[storageId]; - - using ResourceBuilderBaseDataType = typename ResourceBuilder::BaseDataType; - Scope data; - - if constexpr (!std::is_void_v) { - Scope baseData = DataManager::template load(storageId); - if (!baseData) { - const char* baseDataType = abi::__cxa_demangle(typeid(ResourceBuilderBaseDataType).name(), 0, 0, nullptr); - const char* dataType = abi::__cxa_demangle(typeid(T).name(), 0, 0, nullptr); - DEER_CORE_ERROR("Error loading base resource {} for resource {} with id {}", baseDataType, dataType, storageId.c_str()); - return Resource(); - } - data = ResourceBuilder::buildResource(*baseData.get()); - } else { - data = ResourceBuilder::buildResource(); // No base data - } - - Resource resource = Resource::unsafeFromId(resources.size()); - resources.push_back({storageId, std::move(data)}); - resourceCache[storageId] = resource; - - return resource; - } - - static Resource getResource(const std::string& storageId) { - if (resourceCache.contains(storageId)) - return resourceCache[storageId]; - - return Resource(); - } - - static Resource loadResourceFromData(const typename ResourceBuilder::BaseDataType& resourceData, const std::string& storageId) { - if (resourceCache.contains(storageId)) - return resourceCache[storageId]; - - Scope data = ResourceBuilder::buildResource(resourceData); - - Resource resource = Resource::unsafeFromId(resources.size()); - resources.push_back({storageId, std::move(data)}); - resourceCache[storageId] = resource; - - return resource; - } - - static void unloadResources() { - resourceCache.clear(); - resources.clear(); - } - - static inline bool isValid(Resource res) { - return res.resourceId >= 0 && res.resourceId < static_cast(resources.size()); - } - - static inline const std::string& getStorageId(Resource res) { - const static std::string invalid("NULL"); - if (!isValid(res)) - return invalid; - - return resources[res.resourceId].storageId; - } - - static T& getResourceData(Resource res) { - return *resources[res.resourceId].data; - } - }; - - template - std::vector::ResourceData> ResourceManager::resources; - template - std::unordered_map> ResourceManager::resourceCache; -} // namespace Deer diff --git a/Deer/Include/DeerCore/Scripting.h b/Deer/Include/DeerCore/Scripting.h index c5845b0..658dd50 100644 --- a/Deer/Include/DeerCore/Scripting.h +++ b/Deer/Include/DeerCore/Scripting.h @@ -35,7 +35,7 @@ namespace Deer { std::string baseTypeName; std::string moduleName; std::vector events; - SystemDescription(const std::string& _baseTypeName, const std::string& _moduleName, const std::vector& _events = {}) : baseTypeName(_baseTypeName), moduleName(_moduleName), events(_events) {} + SystemDescription(const std::string& _baseTypeName = "", const std::string& _moduleName = "", const std::vector& _events = {}) : baseTypeName(_baseTypeName), moduleName(_moduleName), events(_events) {} }; // Functions called by Engine diff --git a/Deer/Include/DeerCore/Serialization/WorldSettings.h b/Deer/Include/DeerCore/Serialization/WorldSettings.h new file mode 100644 index 0000000..0b383a6 --- /dev/null +++ b/Deer/Include/DeerCore/Serialization/WorldSettings.h @@ -0,0 +1,31 @@ +#pragma once +#include "cereal/cereal.hpp" + +#ifdef DEER_RENDER +#include "DeerRender/Mesh.h" +#include "DeerRender/Shader.h" + +#include "DeerRender/Tools/Memory.h" +#include +#endif + +namespace Deer { + struct WorldSerializationSettings { +#ifdef DEER_RENDER + bool includeServer = false; + bool includeClient = true; + + std::function(const Path&)> meshLoadingFunction = nullptr; + std::function(const Path&)> shaderLoadingFunction = nullptr; +#else + bool includeServer = true; + bool includeClient = false; +#endif + + template + void serialize(Archive& archive) { + archive(CEREAL_NVP(includeServer)); + archive(CEREAL_NVP(includeClient)); + } + }; +} // namespace Deer \ No newline at end of file diff --git a/Deer/Include/DeerCore/Universe.h b/Deer/Include/DeerCore/Universe.h index 7ab53f9..c3a9d2e 100644 --- a/Deer/Include/DeerCore/Universe.h +++ b/Deer/Include/DeerCore/Universe.h @@ -1,4 +1,5 @@ #pragma once +#include "DeerCore/Serialization/WorldSettings.h" #include "DeerCore/Tools/Path.h" namespace Deer { @@ -7,8 +8,9 @@ namespace Deer { namespace Universe { World* createWorld(const WorldSettings&); + World* loadWorldFromJson(const WorldSettings&, WorldSerializationSettings&, const Path&); - void saveWorldInJson(World*, const Path& path); + void saveWorldInJson(World*, WorldSerializationSettings& serializationSettings, const Path& path); void destroyAllWorlds(); void flushDestroyedWorlds(); diff --git a/Deer/Include/DeerRender/DataManagment.h b/Deer/Include/DeerRender/DataManagment.h index 125a73b..677d90a 100644 --- a/Deer/Include/DeerRender/DataManagment.h +++ b/Deer/Include/DeerRender/DataManagment.h @@ -1,2 +1,78 @@ #pragma once -#include "DeerCore/DataManagment.h" \ No newline at end of file +#include "DeerCore/Tools/Memory.h" +#include "DeerCore/Tools/TypeDefs.h" + +#include +#include +#include + +namespace Deer { + + using StorageMetadata = std::unordered_map; + template + concept HasMetadata = requires(const std::string& location) { + { T::loadMetadata(location) } -> std::same_as; + { T::saveMetadata(StorageMetadata{}, location) }; + }; + + class StorageData { + public: + StorageData() = default; + StorageData(uint32_t dataSize) : size(dataSize), data(MakeScope(dataSize)) {} + + inline uint8_t* getData() { return data.get(); } + inline const uint8_t* getData() const { return data.get(); } + inline uint32_t getSize() const { return size; } + inline StorageMetadata& getMetadata() { return metadata; } + + template + Scope deserialize(); + + template + static StorageData serialize(const T&); + + inline explicit operator bool() const { return size != 0; } + + private: + StorageMetadata metadata; + Scope data = nullptr; + uint32_t size = 0; + }; + + template + class StorageBackend { + public: + static StorageData loadData(const std::string& location); + static void saveData(const std::string& location, const StorageData& data); + + static StorageMetadata loadMetadata(const std::string& location); + static void saveMetadata(const StorageMetadata& metadata, const std::string& location); + + static std::vector indexResources(const std::string& location); + }; + + template + class DataManager { + public: + template + static Scope load(const std::string& dataId) { + StorageData data = StorageBackend::loadData(dataId); + + if constexpr (HasMetadata>) { + data.getMetadata() = StorageBackend::loadMetadata(dataId); + data.getMetadata()["dataId"] = dataId; + } + + return data.deserialize(); + } + + template + static void store(const std::string& dataId, T& value) { + StorageData data = StorageData::serialize(value); + StorageBackend::saveData(dataId, data); + if constexpr (HasMetadata>) { + StorageBackend::saveMetadata(data.getMetadata(), dataId); + } + } + }; +} // namespace Deer \ No newline at end of file diff --git a/Deer/Include/DeerRender/Resource.h b/Deer/Include/DeerRender/Resource.h index fd6b8c1..1f2d646 100644 --- a/Deer/Include/DeerRender/Resource.h +++ b/Deer/Include/DeerRender/Resource.h @@ -1,2 +1,140 @@ #pragma once -#include "DeerCore/Resource.h" \ No newline at end of file +#include "DeerRender/DataManagment.h" +#include "DeerRender/Log.h" +#include "DeerRender/Tools/Memory.h" +#include "DeerRender/Tools/Path.h" +#include "DeerRender/Tools/TypeDefs.h" + +#include +#include +#include + +namespace Deer { + template + class ResourceManager; + + template + class Resource { + public: + int32_t getResourceId() const { return resourceId; } + + bool isValid() const { return ResourceManager::isValid(*this); } + T& getData() { return ResourceManager::getResourceData(*this); } + + const std::string& getStorageId() const { return ResourceManager::getStorageId(*this); } + + inline explicit operator bool() const { return resourceId >= 0; } + + static Resource unsafeFromId(int32_t id) { + Resource res; + res.resourceId = id; + return res; + } + + private: + // -1 = no resource loaded + int32_t resourceId = -1; + friend ResourceManager; + }; + + template + class ResourceBuilder { + public: + using BaseDataType = char; + static Scope buildResource(const BaseDataType& baseData) { + static_assert(sizeof(T) == 0, "ResourceBuilder must be specialized for this type T"); + return nullptr; + } + }; + + template + class ResourceManager { + private: + struct ResourceData { + public: + ResourceData(const std::string& _resourceId, Scope&& _data) + : storageId(_resourceId), data(std::move(_data)) {} + + Scope data; + const std::string storageId; + }; + + static std::vector resources; + static std::unordered_map> resourceCache; + + public: + template + static Resource loadResource(const std::string& storageId) { + if (resourceCache.contains(storageId)) + return resourceCache[storageId]; + + using ResourceBuilderBaseDataType = typename ResourceBuilder::BaseDataType; + Scope data; + + if constexpr (!std::is_void_v) { + Scope baseData = DataManager::template load(storageId); + if (!baseData) { + const char* baseDataType = abi::__cxa_demangle(typeid(ResourceBuilderBaseDataType).name(), 0, 0, nullptr); + const char* dataType = abi::__cxa_demangle(typeid(T).name(), 0, 0, nullptr); + DEER_CORE_ERROR("Error loading base resource {} for resource {} with id {}", baseDataType, dataType, storageId.c_str()); + return Resource(); + } + data = ResourceBuilder::buildResource(*baseData.get()); + } else { + data = ResourceBuilder::buildResource(); // No base data + } + + Resource resource = Resource::unsafeFromId(resources.size()); + resources.push_back({storageId, std::move(data)}); + resourceCache[storageId] = resource; + + return resource; + } + + static Resource getResource(const std::string& storageId) { + if (resourceCache.contains(storageId)) + return resourceCache[storageId]; + + return Resource(); + } + + static Resource loadResourceFromData(const typename ResourceBuilder::BaseDataType& resourceData, const std::string& storageId) { + if (resourceCache.contains(storageId)) + return resourceCache[storageId]; + + Scope data = ResourceBuilder::buildResource(resourceData); + + Resource resource = Resource::unsafeFromId(resources.size()); + resources.push_back({storageId, std::move(data)}); + resourceCache[storageId] = resource; + + return resource; + } + + static void unloadResources() { + resourceCache.clear(); + resources.clear(); + } + + static inline bool isValid(Resource res) { + return res.resourceId >= 0 && res.resourceId < static_cast(resources.size()); + } + + static inline const std::string& getStorageId(Resource res) { + const static std::string invalid("NULL"); + if (!isValid(res)) + return invalid; + + return resources[res.resourceId].storageId; + } + + static T& getResourceData(Resource res) { + return *resources[res.resourceId].data; + } + }; + + template + std::vector::ResourceData> ResourceManager::resources; + template + std::unordered_map> ResourceManager::resourceCache; +} // namespace Deer diff --git a/Deer/src/DeerCore/Serialization/Entity.h b/Deer/src/DeerCore/Serialization/Entity.h index ccc897d..6e97bf5 100644 --- a/Deer/src/DeerCore/Serialization/Entity.h +++ b/Deer/src/DeerCore/Serialization/Entity.h @@ -6,6 +6,11 @@ #include "DeerCore/Serialization/Components/TransformComponent.h" +#ifdef DEER_RENDER +#include "DeerRender/Serialization/Components/MeshComponentSerialization.h" +#include "DeerRender/Serialization/Components/ShaderComponentSerialization.h" +#endif + #include "cereal/cereal.hpp" #include @@ -16,18 +21,34 @@ namespace Deer { uint32_t entityId; template - void saveComponent(Archive& archive, Entity& entity) { + void saveComponent(Archive& archive, Entity& entity, const char* name) const { std::string containsComponentString = "Contains_"; - containsComponentString += typeid(T).name(); + containsComponentString += name; bool hasComponent = entity.hasComponent(); archive(cereal::make_nvp(containsComponentString.c_str(), hasComponent)); if (hasComponent) { - S serialization; - serialization.component = entity.getComponent(); - serialization.settings = settings; + S serialization{ + .component = entity.getComponent(), + .settings = settings}; - archive(cereal::make_nvp(typeid(T).name(), serialization)); + archive(cereal::make_nvp(name, serialization)); + } + } + + template + void loadComponent(Archive& archive, Entity& entity, const char* name) { + std::string containsComponentString = "Contains_"; + containsComponentString += name; + + bool hasComponent; + archive(cereal::make_nvp(containsComponentString.c_str(), hasComponent)); + if (hasComponent) { + S serialization{ + .component = entity.addComponent(), + .settings = settings}; + + archive(cereal::make_nvp(name, serialization)); } } @@ -43,14 +64,46 @@ namespace Deer { archive(cereal::make_nvp("NetworkBehaviour", tag.networkBehaviour)); archive(cereal::make_nvp("Parent", relation.parent_id)); - TransformComponentSerialization serialization; - serialization.settings = settings; - serialization.component = entity.getComponent(); - archive(cereal::make_nvp(typeid(TransformComponent).name(), serialization)); + TransformComponentSerialization transformSerialization{ + .settings = settings, + .component = entity.getComponent()}; + archive(cereal::make_nvp("TransformComponent", transformSerialization)); + + if (settings.includeClient) { +#ifdef DEER_RENDER + saveComponent(archive, entity, "MeshComponent"); + saveComponent(archive, entity, "ShaderComponent"); +#else + DEER_CORE_ERROR("Can not include client on Deer Core Headless Compile"); +#endif + } } template void load(Archive& archive) { + archive(cereal::make_nvp("Id", entityId)); + Entity& entity = entityEnvironment->createEntityWithId(entityId); + + TagComponent& tag = entity.getComponent(); + RelationshipComponent& relation = entity.getComponent(); + + archive(cereal::make_nvp("Tag", tag.tag)); + archive(cereal::make_nvp("NetworkBehaviour", tag.networkBehaviour)); + archive(cereal::make_nvp("Parent", tag.networkBehaviour)); + + TransformComponentSerialization transformSerialization{ + .settings = settings, + .component = entity.getComponent()}; + archive(cereal::make_nvp("TransformComponent", transformSerialization)); + + if (settings.includeClient) { +#ifdef DEER_RENDER + loadComponent(archive, entity, "MeshComponent"); + loadComponent(archive, entity, "ShaderComponent"); +#else + DEER_CORE_ERROR("Can not include client on Deer Core Headless Compile"); +#endif + } } }; } // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerCore/Serialization/EntityEnvironment.h b/Deer/src/DeerCore/Serialization/EntityEnvironment.h index a926485..b82cbb6 100644 --- a/Deer/src/DeerCore/Serialization/EntityEnvironment.h +++ b/Deer/src/DeerCore/Serialization/EntityEnvironment.h @@ -18,7 +18,7 @@ namespace Deer { void save(Archive& archive) const { std::vector entities; - size_t entityIndex = 0; + uint32_t entityIndex = 0; size_t remainingEntities = entityEnvironment->getEntityCount(); while (remainingEntities > 0) { if (!entityEnvironment->entityExists(entityIndex)) { @@ -43,13 +43,12 @@ namespace Deer { entityIndex++; } - entities.push_back({}); + EntitySerialization entityS{ + .settings = settings, + .entityEnvironment = entityEnvironment, + .entityId = entityIndex}; - EntitySerialization& entityS = entities.push_back(); - - entityS.settings = settings; - entityS.entityId = entityEnvironment; - entityS.entityId = entityIndex; + entities.push_back(entityS); remainingEntities--; entityIndex++; @@ -63,14 +62,20 @@ namespace Deer { template void load(Archive& archive) { size_t entitySize; - archive(cereal::make_nvp("Entities", entitySize)); + archive(cereal::make_size_tag(entitySize)); + std::vector entities; for (size_t i = 0; i < entitySize; i++) { - EntitySerialization entityS; - entityS.entityEnvironment = entityEnvironment; - entityS.settings = settings; - + EntitySerialization entityS{.settings = settings, .entityEnvironment = entityEnvironment}; archive(entityS); + + entities.push_back(entityS.entityId); + } + + for (uint32_t entity_id : entities) { + Entity& entity = entityEnvironment->getEntity(entity_id); + RelationshipComponent& tag = entity.getComponent(); + entity.setParent(entityEnvironment->getEntity(tag.parent_id)); } } }; diff --git a/Deer/src/DeerCore/Serialization/World.h b/Deer/src/DeerCore/Serialization/World.h index 8557aed..7949fe4 100644 --- a/Deer/src/DeerCore/Serialization/World.h +++ b/Deer/src/DeerCore/Serialization/World.h @@ -8,18 +8,15 @@ namespace Deer { class World; struct WorldSerialization { - WorldSerializationSettings settings; - EntityEnvironment* entityEnv; - uint32_t entityId; + WorldSerializationSettings& settings; World* world; template void serialize(Archive& archive) { - EntityEnvironmentSerialization entityEnvironment; - entityEnvironment.settings = settings; - entityEnvironment.entityEnvironment = world->entityEnvironment.get(); + EntityEnvironmentSerialization entityEnvironment{ + .settings = settings, + .entityEnvironment = world->entityEnvironment.get()}; - archive(cereal::make_nvp("SerializationSettings", settings)); archive(cereal::make_nvp("EntityEnvironment", entityEnvironment)); } }; diff --git a/Deer/src/DeerCore/Serialization/WorldSettings.h b/Deer/src/DeerCore/Serialization/WorldSettings.h deleted file mode 100644 index 57afb0c..0000000 --- a/Deer/src/DeerCore/Serialization/WorldSettings.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include "cereal/cereal.hpp" - -namespace Deer { - struct WorldSerializationSettings { - bool includeServer; - bool includeClient; - - WorldSerializationSettings() { -#ifdef DEER_RENDER - includeServer = false; - includeClient = true; -#else - includeServer = true; - includeClient = false; -#endif - }; - - template - void serialize(Archive& archive) { - archive(CEREAL_NVP(includeServer)); - archive(CEREAL_NVP(includeClient)); - } - }; -} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerCore/Universe/UniverseSerialization.cpp b/Deer/src/DeerCore/Universe/UniverseSerialization.cpp index e8fafee..8f01290 100644 --- a/Deer/src/DeerCore/Universe/UniverseSerialization.cpp +++ b/Deer/src/DeerCore/Universe/UniverseSerialization.cpp @@ -1,6 +1,35 @@ #include "DeerCore/Universe.h" +#include "DeerCore/Serialization/World.h" +#include "cereal/archives/json.hpp" + +#include + namespace Deer { - void Universe::saveWorldInJson(World* world, const Path& path) { + void Universe::saveWorldInJson(World* world, WorldSerializationSettings& serializationSettings, const Path& path) { + std::ofstream file(path); + cereal::JSONOutputArchive archive(file); + + WorldSerialization worldSerialization{ + .settings = serializationSettings, + .world = world}; + + archive(cereal::make_nvp("SerializationSettings", serializationSettings)); + archive(cereal::make_nvp("World", worldSerialization)); + } + + World* Universe::loadWorldFromJson(const WorldSettings& worldSettings, WorldSerializationSettings& serializationSettings, const Path& path) { + std::ifstream file(path); + cereal::JSONInputArchive archive(file); + + World* world = Universe::createWorld(worldSettings); + WorldSerialization worldSerialization{ + .settings = serializationSettings, + .world = world}; + + archive(cereal::make_nvp("SerializationSettings", serializationSettings)); + archive(cereal::make_nvp("World", worldSerialization)); + + return world; } } // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerCore/World/World.cpp b/Deer/src/DeerCore/World/World.cpp index efa7e23..cfcd2af 100755 --- a/Deer/src/DeerCore/World/World.cpp +++ b/Deer/src/DeerCore/World/World.cpp @@ -20,7 +20,7 @@ namespace Deer { } World::~World() { - DEER_CORE_ASSERT(executingState == WorldState::Stopped, "Invalid executing state while destroying world"); + DEER_CORE_ASSERT(executingState == WorldState::ReadyToDestroy, "Invalid executing state while destroying world"); } void World::stopExecution() { diff --git a/Deer/src/DeerRender/Core/Engine.cpp b/Deer/src/DeerRender/Core/Engine.cpp index a38b42b..e02e976 100644 --- a/Deer/src/DeerRender/Core/Engine.cpp +++ b/Deer/src/DeerRender/Core/Engine.cpp @@ -65,6 +65,10 @@ namespace Deer { RenderCommand::init(); RenderUtils::initializeRenderUtils(); + Builtin::cube(); + Builtin::simpleShader(); + Builtin::sphere(); + ImGuiLayer::init(*window); } diff --git a/Deer/src/DeerRender/Serialization/Components/MeshComponentSerialization.h b/Deer/src/DeerRender/Serialization/Components/MeshComponentSerialization.h new file mode 100644 index 0000000..de532b7 --- /dev/null +++ b/Deer/src/DeerRender/Serialization/Components/MeshComponentSerialization.h @@ -0,0 +1,32 @@ +#pragma once +#include "DeerCore/Serialization/WorldSettings.h" + +#include "DeerRender/Components.h" + +#include "cereal/cereal.hpp" + +namespace Deer { + struct MeshComponentSerialization { + WorldSerializationSettings& settings; + MeshComponent& component; + + template + void save(Archive& archive) const { + archive(cereal::make_nvp("IsActive", component.active)); + archive(cereal::make_nvp("Mesh", component.mesh.getStorageId())); + } + + template + void load(Archive& archive) { + std::string storageId; + + archive(cereal::make_nvp("IsActive", component.active)); + archive(cereal::make_nvp("Mesh", storageId)); + + Scope meshData = settings.meshLoadingFunction(storageId); + + Resource mesh = ResourceManager::loadResourceFromData(*meshData.get(), storageId); + component.mesh = mesh; + } + }; +} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerRender/Serialization/Components/ShaderComponentSerialization.h b/Deer/src/DeerRender/Serialization/Components/ShaderComponentSerialization.h new file mode 100644 index 0000000..89f574c --- /dev/null +++ b/Deer/src/DeerRender/Serialization/Components/ShaderComponentSerialization.h @@ -0,0 +1,30 @@ +#pragma once +#include "DeerCore/Serialization/WorldSettings.h" + +#include "DeerRender/Components.h" + +#include "cereal/cereal.hpp" + +namespace Deer { + struct ShaderComponentSerialization { + WorldSerializationSettings& settings; + ShaderComponent& component; + + template + void save(Archive& archive) const { + archive(cereal::make_nvp("Shader", component.shader.getStorageId())); + } + + template + void load(Archive& archive) { + std::string storageId; + + archive(cereal::make_nvp("Shader", storageId)); + + Scope shaderData = settings.shaderLoadingFunction(storageId); + + Resource shader = ResourceManager::loadResourceFromData(*shaderData.get(), storageId); + component.shader = shader; + } + }; +} // namespace Deer \ No newline at end of file diff --git a/Deer/src/DeerRender/Serialization/Components/TransformComponent copy.h b/Deer/src/DeerRender/Serialization/Components/TransformComponent copy.h deleted file mode 100644 index 677616e..0000000 --- a/Deer/src/DeerRender/Serialization/Components/TransformComponent copy.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include "DeerCore/Serialization/WorldSettings.h" - -#include "DeerRender/Components.h" - -#include "cereal/cereal.hpp" - -namespace Deer { - struct MeshComponentSerialization { - WorldSerializationSettings& settings; - TransformComponent& component; - - template - void serialize(Archive& archive) { - archive(cereal::make_nvp("Position", component.position)); - archive(cereal::make_nvp("Scale", component.scale)); - archive(cereal::make_nvp("Rotation", component.rotation)); - } - }; -} // namespace Deer \ No newline at end of file diff --git a/DeerStudio/headers/DeerStudio/DeerStudio.h b/DeerStudio/headers/DeerStudio/DeerStudio.h index 47c92dc..a4c6cbe 100755 --- a/DeerStudio/headers/DeerStudio/DeerStudio.h +++ b/DeerStudio/headers/DeerStudio/DeerStudio.h @@ -5,9 +5,13 @@ int main(int, char**); namespace Deer { + class World; + namespace DeerStudio { - void onRender(); - void onUpdate(); + extern World* world; + + void worldUpdate(World&); + void worldRender(World&); void onEvent(Event& e); void main(); @@ -16,5 +20,6 @@ namespace Deer { // Other void onPanelMenuBar(); + void worldManagerMenu(); } // namespace DeerStudio } // namespace Deer diff --git a/DeerStudio/headers/DeerStudio/StudioAPI.h b/DeerStudio/headers/DeerStudio/StudioAPI.h index d860a8d..ed1537e 100644 --- a/DeerStudio/headers/DeerStudio/StudioAPI.h +++ b/DeerStudio/headers/DeerStudio/StudioAPI.h @@ -24,6 +24,5 @@ namespace Deer { CScriptDictionary* setResourceMetadata(std::string& resource); ResourceType getResourceType(std::string&); - } // namespace StudioAPI } // namespace Deer \ No newline at end of file diff --git a/DeerStudio/headers/DeerStudio/StudioPanel.h b/DeerStudio/headers/DeerStudio/StudioPanel.h index 3c5fdf6..e06bd83 100644 --- a/DeerStudio/headers/DeerStudio/StudioPanel.h +++ b/DeerStudio/headers/DeerStudio/StudioPanel.h @@ -4,7 +4,8 @@ namespace Deer { class World; namespace StudioPanel { - void init(World*); + void init(); + void setWorld(World*); void update(); void render(); diff --git a/DeerStudio/src/DeerStudio/DeerStudio.cpp b/DeerStudio/src/DeerStudio/DeerStudio.cpp index d2054a9..9367d3e 100644 --- a/DeerStudio/src/DeerStudio/DeerStudio.cpp +++ b/DeerStudio/src/DeerStudio/DeerStudio.cpp @@ -16,7 +16,7 @@ namespace Deer { class FrameBuffer; namespace DeerStudio { - Universe::WorldHandle mainWorld; + World* world; void onUpdate(); void onRender(); @@ -29,6 +29,7 @@ namespace Deer { void main() { Engine::init(); Engine::setEventCallback(DeerStudio::onEvent); + StudioPanel::init(); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20, 20)); initializeFonts(); @@ -41,10 +42,12 @@ namespace Deer { .renderFrequency = 166, }; - mainWorld = Universe::createWorld(worldSettings); - StudioPanel::init(&Universe::getWorld(mainWorld)); + world = Universe::createWorld(worldSettings); - Universe::getWorld(mainWorld).execute(); + while (world) { + StudioPanel::setWorld(world); + world->execute(); + } Engine::shutdown(); } // namespace DeerStudio @@ -80,8 +83,7 @@ namespace Deer { } static bool p_open = true; - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, - ImVec2(0.0f, 0.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); ImGui::Begin("DockSpace Demo", &p_open, window_flags); @@ -93,17 +95,17 @@ namespace Deer { ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10)); if (ImGui::BeginMenuBar()) { - if (ImGui::BeginMenu("Panel")) { - onPanelMenuBar(); + if (ImGui::BeginMenu("World")) { + DeerStudio::worldManagerMenu(); ImGui::EndMenu(); } - if (ImGui::MenuItem("Reload Editor")) { - } + ImGui::EndMenuBar(); } ImGui::PopStyleVar(); - StudioPanel::render(); + if (world.getExecutionState() == Deer::WorldState::Executing) + StudioPanel::render(); ImGui::End(); @@ -117,10 +119,11 @@ namespace Deer { } bool onWindowCloseEvent(WindowCloseEvent&) { - Universe::getWorld(mainWorld).stopExecution(); + world->stopExecution(); + world = nullptr; return true; } } // namespace DeerStudio } // namespace Deer -int main(int argc, char** args) { Deer::DeerStudio::main(); } +int main(int argc, char** args) { Deer::DeerStudio::main(); } \ No newline at end of file diff --git a/DeerStudio/src/DeerStudio/StudioPanel.cpp b/DeerStudio/src/DeerStudio/StudioPanel.cpp index 20e5d1d..3bd4920 100644 --- a/DeerStudio/src/DeerStudio/StudioPanel.cpp +++ b/DeerStudio/src/DeerStudio/StudioPanel.cpp @@ -13,12 +13,15 @@ namespace Deer { void renderSystem(ScriptSystem* system); } // namespace StudioPanel - void StudioPanel::init(World* world) { + void StudioPanel::init() { StudioScripting::registerStudioScripting(); Scripting::registerInterface("Panel"); Scripting::registerInterfaceFunction("Panel", "onImGui", Scripting::EventType::void_event); Scripting::compileFiles("Editor/Scripts", "Editor"); + } + + void StudioPanel::setWorld(World* world) { Scripting::SystemDescription systemDescription("Panel", "Editor"); systemDescription.events.push_back(Scripting::SystemEvent("onInit", Scripting::EventType::void_event)); systemDescription.events.push_back(Scripting::SystemEvent("onShutdown", Scripting::EventType::void_event)); @@ -67,5 +70,6 @@ namespace Deer { void StudioPanel::shutdown() { editorInstance->executeOnGroup_voidEvent(1); + studioPanelEnvironment.release(); } } // namespace Deer \ No newline at end of file diff --git a/DeerStudio/src/DeerStudio/WorldManager.cpp b/DeerStudio/src/DeerStudio/WorldManager.cpp new file mode 100644 index 0000000..4df2be2 --- /dev/null +++ b/DeerStudio/src/DeerStudio/WorldManager.cpp @@ -0,0 +1,47 @@ +#include "DeerCore/Serialization/WorldSettings.h" +#include "DeerCore/Tools/Memory.h" +#include "DeerCore/Universe.h" + +#include "DeerStudio/EditorDataImporter.h" +#include "DeerStudio/EditorDataSource.h" +#include "DeerStudio/StudioPanel.h" + +#include "DeerCore/World.h" +#include "DeerStudio/DeerStudio.h" +#include "imgui.h" + +namespace Deer { + template + Scope loadResourceData(const Path& storageId) { + StorageData storageData = StorageBackend::loadData(storageId); + return storageData.deserialize(); + } + + void DeerStudio::worldManagerMenu() { + if (ImGui::MenuItem("Save world")) { + WorldSerializationSettings serializationSettings{ + .includeServer = true, + .includeClient = true}; + Universe::saveWorldInJson(world, serializationSettings, "Worlds/world.json"); + } + + if (ImGui::MenuItem("Load world")) { + StudioPanel::shutdown(); + world->destroy(); + + WorldSettings worldSettings = { + .updateCallback = worldUpdate, + .updateFrequency = 60, + .renderCallback = worldRender, + .renderFrequency = 166, + }; + + WorldSerializationSettings serializationSettings{ + .meshLoadingFunction = loadResourceData, + .shaderLoadingFunction = loadResourceData}; + + World* world_new = Universe::loadWorldFromJson(worldSettings, serializationSettings, "Worlds/world.json"); + world = world_new; + } + } +} // namespace Deer \ No newline at end of file diff --git a/Worlds/world.json b/Worlds/world.json new file mode 100644 index 0000000..d04495e --- /dev/null +++ b/Worlds/world.json @@ -0,0 +1,135 @@ +{ + "SerializationSettings": { + "includeServer": true, + "includeClient": true + }, + "World": { + "EntityEnvironment": [ + { + "Id": 0, + "Tag": "root", + "NetworkBehaviour": 0, + "Parent": 0, + "TransformComponent": { + "Position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "Scale": { + "x": 1.0, + "y": 1.0, + "z": 1.0 + }, + "Rotation": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 1.0 + } + }, + "Contains_MeshComponent": false, + "Contains_ShaderComponent": false + }, + { + "Id": 1, + "Tag": "node", + "NetworkBehaviour": 0, + "Parent": 0, + "TransformComponent": { + "Position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "Scale": { + "x": 1.0, + "y": 1.0, + "z": 1.0 + }, + "Rotation": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 1.0 + } + }, + "Contains_MeshComponent": true, + "MeshComponent": { + "IsActive": true, + "Mesh": "Builtin:Cube" + }, + "Contains_ShaderComponent": true, + "ShaderComponent": { + "Shader": "Builtin:SimpleShader" + } + }, + { + "Id": 2, + "Tag": "node", + "NetworkBehaviour": 0, + "Parent": 0, + "TransformComponent": { + "Position": { + "x": 2.299999952316284, + "y": 0.0, + "z": 0.0 + }, + "Scale": { + "x": 1.0, + "y": 1.0, + "z": 1.0 + }, + "Rotation": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 1.0 + } + }, + "Contains_MeshComponent": true, + "MeshComponent": { + "IsActive": true, + "Mesh": "Builtin:Sphere" + }, + "Contains_ShaderComponent": true, + "ShaderComponent": { + "Shader": "Builtin:SimpleShader" + } + }, + { + "Id": 3, + "Tag": "node", + "NetworkBehaviour": 0, + "Parent": 0, + "TransformComponent": { + "Position": { + "x": -3.700000047683716, + "y": 0.0, + "z": 0.0 + }, + "Scale": { + "x": 1.0, + "y": 1.0, + "z": 1.0 + }, + "Rotation": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "w": 1.0 + } + }, + "Contains_MeshComponent": true, + "MeshComponent": { + "IsActive": true, + "Mesh": "train-locomotive-a.obj" + }, + "Contains_ShaderComponent": true, + "ShaderComponent": { + "Shader": "shader_darkBlue.glsl" + } + } + ] + } +} \ No newline at end of file diff --git a/imgui.ini b/imgui.ini index 29a2eb4..1bcba21 100644 --- a/imgui.ini +++ b/imgui.ini @@ -1,6 +1,6 @@ [Window][DockSpace Demo] Pos=0,0 -Size=1920,1011 +Size=2560,1371 Collapsed=0 [Window][Debug##Default] @@ -10,30 +10,30 @@ Collapsed=0 [Window][ViewportPanel] Pos=561,26 -Size=934,493 +Size=1574,853 Collapsed=0 DockId=0x00000005,0 [Window][PropertiesPanel] -Pos=1497,26 -Size=423,493 +Pos=2137,26 +Size=423,853 Collapsed=0 DockId=0x00000006,0 [Window][ResourceExplorer] -Pos=0,521 -Size=1920,490 +Pos=0,881 +Size=2560,490 Collapsed=0 DockId=0x00000004,0 [Window][TreePanel] Pos=0,26 -Size=559,493 +Size=559,853 Collapsed=0 DockId=0x00000001,0 [Docking][Data] -DockSpace ID=0x0AC2E849 Window=0xD0388BC8 Pos=0,26 Size=1920,985 Split=Y +DockSpace ID=0x0AC2E849 Window=0xD0388BC8 Pos=0,26 Size=2560,1345 Split=Y DockNode ID=0x00000003 Parent=0x0AC2E849 SizeRef=1920,493 Split=X DockNode ID=0x00000001 Parent=0x00000003 SizeRef=559,985 Selected=0x16E3C1E7 DockNode ID=0x00000002 Parent=0x00000003 SizeRef=1359,985 Split=X