diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d6e0a6..9bd95eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,6 @@ endif() add_subdirectory(FastRTTI) add_subdirectory(glfw) add_subdirectory(Core) -add_subdirectory(ModuleLib) add_subdirectory(TestGame) add_subdirectory(ProjectGenerator) +add_subdirectory(Tests) diff --git a/Core/Core/CoreCallBacks.h b/Core/Core/CoreCallBacks.h deleted file mode 100644 index 9a0ecfd..0000000 --- a/Core/Core/CoreCallBacks.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -struct CoreCallBacks -{ - void (*Quit)(); -}; \ No newline at end of file diff --git a/Core/Core/CoreInstance.cpp b/Core/Core/CoreInstance.cpp index e6fb345..ae6eb40 100644 --- a/Core/Core/CoreInstance.cpp +++ b/Core/Core/CoreInstance.cpp @@ -1,6 +1,6 @@ -#include "CoreInstance.h" +#include "CoreInstance.hpp" -#include "SystemCalls.h" +#include "SystemCalls.hpp" #include #include @@ -8,12 +8,9 @@ #include #include -#include "RenderEngine.h" -#include "Game/GameInstance.h" -#include "Log/Log.h" -#include "Game/SaveMap/SaveMap.h" - -CoreInstance* CoreInstance::self = nullptr; +#include "RenderEngine/RenderEngine.hpp" +#include "Game/GameInstance.hpp" +#include "Game/SaveMap/SaveMap.hpp" extern GameInstance* GameFactory(CoreInstance&); @@ -31,26 +28,24 @@ void CoreInstance::MainConfig::load(std::shared_ptr save) min_CPU_count = save->GetInteger("min_CPU_count"); } -void CoreInstance::Quit_callback() -{ - self->game_->quit(); -} - CoreInstance::CoreInstance() { - self = this; - - callbacks_.Quit = &Quit_callback; - countCPU_ = System::getCountCPU(); memorySize_ = System::getMemorySize(); std::ifstream main_config_file(main_config_name); + std::string payload; + if (main_config_file.fail()) throw std::runtime_error("Fail open main config file"); - std::string payload; - std::getline(main_config_file, payload); + main_config_file.seekg(0, std::ios::end); + size_t size_config = main_config_file.tellg(); + main_config_file.seekg(0, std::ios::beg); + payload.resize(size_config); + + main_config_file.read(payload.data(), static_cast(payload.size())); + main_config_file.close(); SaveMap load_main_config(payload); main_config_.load(std::make_shared(load_main_config)); @@ -63,53 +58,46 @@ CoreInstance::CoreInstance() window_ = glfwCreateWindow(800, 600, main_config_.game_name.c_str(), nullptr, nullptr); if (window_ == nullptr) { - glfwTerminate(); - throw std::runtime_error("Fail create window"); + std::cout << "[!] Init render engine: Fail create window\n"; + return; } - render_engine_ = new RenderEngine(*this, window_); - - game_ = GameFactory(*this); - if (game_ == nullptr) - throw std::runtime_error("Fail create game instance!"); + try { + render_engine_ = new RenderEngine(*this, window_); + } catch (const std::exception& e) + { + std::cout << "[!] Init render engine: " << e.what() << '\n'; + return; + } + + try + { + game_ = GameFactory(*this); + } catch (const std::exception& e) + { + std::cout << "[!] Init game instance: " << e.what() << '\n'; + return; + } + is_ready = true; } CoreInstance::~CoreInstance() { - for (auto& module : modules_) - System::QuitModule(module.handler); modules_.clear(); - delete render_engine_; delete game_; + delete render_engine_; + + glfwDestroyWindow(window_); + glfwTerminate(); } void CoreInstance::start() { - for (auto& name : main_config_.modules_names) - { - try - { - void* handler = System::InitModule(name.c_str(), &callbacks_); - modules_.push_back(Module {name.c_str(), handler}); - } catch (const std::exception& e) - { - std::cout << e.what() << '\n'; - } - } - - for (auto& module : modules_) - { - try - { - System::StartModule(module.handler); - } catch (const std::exception& e) - { - std::cout << e.what() << '\n'; - } - } - std::thread game_thread(&GameInstance::start, game_); + + // Main thread is render render_engine_->start(); + game_->stop(); game_thread.join(); } @@ -120,40 +108,3 @@ void CoreInstance::quit() render_engine_->stop_render(); } -void* CoreInstance::getHandlerModule(const char* name) const -{ - for (const auto& module : modules_) - { - if (std::strcmp(module.name, name) == 0) - return module.handler; - } - throw std::runtime_error("Module not found"); -} - -void* CoreInstance::enableModule(const char* name) -{ - for (const auto& module : modules_) - { - if (std::strcmp(module.name, name) == 0) - throw std::runtime_error("Module already enabled"); - } - - void* module = System::InitModule(name, &callbacks_); - modules_.push_back({ name, module }); - return module; -} - -void CoreInstance::disableModule(const char* name) -{ - for (auto i = modules_.cbegin(); i != modules_.cend(); ++i) - { - if (std::strcmp(i->name, name) == 0) - { - System::QuitModule(i->handler); - modules_.erase(i); - break; - } - } - - throw std::runtime_error("Module not found"); -} diff --git a/Core/Core/CoreInstance.h b/Core/Core/CoreInstance.hpp similarity index 57% rename from Core/Core/CoreInstance.h rename to Core/Core/CoreInstance.hpp index 43ee59f..260e0bd 100644 --- a/Core/Core/CoreInstance.h +++ b/Core/Core/CoreInstance.hpp @@ -6,13 +6,15 @@ #include #include "Game/SaveMap/ISave.h" -#include "Core/CoreCallBacks.h" class SaveMap; class RenderEngine; class GameInstance; struct GLFWwindow; +/* + * Внимательно следите, что бы у ваших объектов была "мягкая" зависимость + */ class CoreInstance { struct Module { const char* name; @@ -44,40 +46,19 @@ class CoreInstance { RenderEngine* render_engine_; GameInstance* game_; - static CoreInstance* self; - CoreCallBacks callbacks_; - -#pragma region Callbacks - static void Quit_callback(); -#pragma endregion + bool is_ready = false; public: CoreInstance(); ~CoreInstance(); void start(); void quit(); - + + bool IsReady() const { return is_ready; } int getCountCPU() const { return countCPU_; } double getMemorySize() const { return memorySize_; } const std::string& getBaseWorldName() const { return main_config_.base_world; } const std::string& getGameName() const { return main_config_.game_name; } - - /** - * @throws std::runtime_error if module isn't enabled - * @throws std::runtime_error if module not found - * @return module handler - */ - void* getHandlerModule(const char* name) const noexcept(false); - /** - * @throws std::runtime_error if the module already enabled - * @throws std::runtime_error if the module isn't found - * @throws std::runtime_error if the module doesn't contain InitModule or StartModule - * @retuen module handler - */ - void* enableModule(const char* name) noexcept(false); - /** - * @throws std::runtime_error if the module isn't found - * @throws std::runtime_error module isn't contain QuitModule function - */ - void disableModule(const char* name) noexcept(false); + GameInstance* GetGameInstance() const { return game_; } + RenderEngine* GetRenderEngine() const { return render_engine_; } }; diff --git a/Core/Core/RenderEngine/ModelManager.cpp b/Core/Core/RenderEngine/ModelManager.cpp new file mode 100644 index 0000000..5d51dcd --- /dev/null +++ b/Core/Core/RenderEngine/ModelManager.cpp @@ -0,0 +1,107 @@ +#include "ModelManager.hpp" + +#include "Log/Log.hpp" + +ModelManager::StaticModel::StaticModel(const std::vector& voxels, std::string name): +name_(std::move(name)), +voxels_(voxels) +{ + glm::ivec3 sum_moments{0, 0, 0}; + int sum_masses = 0; + + for (auto& i : voxels_) + { + sum_moments += glm::ivec3{i.loc.x * i.mass, i.loc.y * i.mass, i.loc.z * i.mass}; + sum_masses += i.mass; + } + + if(sum_masses != 0) + sum_moments /= sum_masses; + else if (!voxels_.empty()) + { + sum_moments.x /= static_cast(voxels_.size()); + sum_moments.y /= static_cast(voxels_.size()); + sum_moments.z /= static_cast(voxels_.size()); + } + + mass_center_ = sum_moments; +} + +ModelManager::StaticModel::~StaticModel() +{ + OnDestroy.Call(name_); +} + +ModelManager::owner_counter::owner_counter(const owner_counter& other) : counter(other.counter.load()), model(other.model) +{ +} + +unsigned int ModelManager::FNV1aHash(const char* buf) +{ + unsigned int h_val = 0x811c9dc5; + + while (*buf) + { + h_val ^= static_cast(*buf++); + h_val *= 0x01000193; + } + + return h_val; +} + +void ModelManager::OnDestroySometimeModelCaller(const std::string& name) +{ + Loging::Log("Free model: " + name); + OnDestroySometimeModel.Call(name); +} + +ModelManager::~ModelManager() +{ + for (const auto& [it, counter] : models) + { + counter.model->OnDestroy.unbind(this, &ModelManager::OnDestroySometimeModelCaller); + } + models.clear(); +} + +ModelManager::StaticModel* ModelManager::LoadModel(const std::string& name) +{ + if (name.empty()) + return nullptr; + unsigned int hash = FNV1aHash(name.c_str()); + auto counter = models.find(hash); + if (counter != models.cend()) + { + ++counter->second.counter; + return counter->second.model; + } + + Loging::Log("Load new model: " + name); + + std::vector model_data; + // Load model_data + owner_counter new_counter; + new_counter.counter.store(1); + new_counter.model = new StaticModel(model_data, name); + new_counter.model->OnDestroy.bind(this, &ModelManager::OnDestroySometimeModelCaller); + models.try_emplace(hash, new_counter); + OnLoadSometimeModel.Call(new_counter.model); + return new_counter.model; +} + +void ModelManager::FreeModel(const std::string& name) +{ + if (name.empty()) + return; + + unsigned int hash = FNV1aHash(name.c_str()); + auto counter = models.find(hash); + --counter->second.counter; + + StaticModel* model = counter->second.model; + if (counter->second.counter.load() == 0) + { + models.erase(hash); + delete model; + } +} diff --git a/Core/Core/RenderEngine/ModelManager.hpp b/Core/Core/RenderEngine/ModelManager.hpp new file mode 100644 index 0000000..77fad10 --- /dev/null +++ b/Core/Core/RenderEngine/ModelManager.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include +#include +#include +#include +#include + +class ModelManager +{ +public: + struct Voxel + { + glm::ivec3 loc, color; + int mass; + }; + class StaticModel + { + std::string name_; + std::vector voxels_; + glm::vec3 mass_center_; + public: + Delegate OnDestroy; + + StaticModel(const std::vector& voxels, std::string name); + ~StaticModel(); + + const std::vector& GetVoxels() const { return voxels_; } + glm::vec3 GetMassCenter() const { return mass_center_; } + const std::string& GetName() const { return name_; } + }; + + struct owner_counter + { + std::atomic_ullong counter; + StaticModel* model; + + owner_counter() = default; + owner_counter(const owner_counter& other); + }; + +private: + + std::unordered_map models; + + static unsigned int FNV1aHash (const char *buf); + + void OnDestroySometimeModelCaller(const std::string& name); + +public: + Delegate OnDestroySometimeModel; + Delegate OnLoadSometimeModel; + + ~ModelManager(); + + StaticModel* LoadModel(const std::string& name); + void FreeModel(const std::string& name); +}; \ No newline at end of file diff --git a/Core/Core/RenderEngine.cpp b/Core/Core/RenderEngine/RenderEngine.cpp similarity index 96% rename from Core/Core/RenderEngine.cpp rename to Core/Core/RenderEngine/RenderEngine.cpp index d4c4d5c..ef3089c 100644 --- a/Core/Core/RenderEngine.cpp +++ b/Core/Core/RenderEngine/RenderEngine.cpp @@ -1,12 +1,16 @@ -#include "RenderEngine.h" +#include "RenderEngine.hpp" #include #include #include #include -#include "CoreInstance.h" -#include "Log/Log.h" +#include "Core/CoreInstance.hpp" +#include "Log/Log.hpp" + +#include "Game/GameInstance.hpp" +#include "Game/World/World.hpp" +#include "Game/Actors/Mesh/Mesh.hpp" #include "GLFW/glfw3.h" @@ -23,7 +27,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( std::string msg = "validation layer: "; msg += pCallbackData->pMessage; - Log(msg); + Loging::Log(msg); return VK_FALSE; } @@ -78,10 +82,13 @@ VkVertexInputBindingDescription RenderEngine::Vertex::get_binding_description() std::array RenderEngine::Vertex::get_vertex_attribute_descriptions() { std::array descriptions; + // Bind vertex loc descriptions[0].binding = 0; descriptions[0].location = 0; descriptions[0].format = VK_FORMAT_R32G32_SFLOAT; descriptions[0].offset = offsetof(Vertex, pos); + + // Bind color descriptions[1].binding = 0; descriptions[1].location = 1; descriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT; @@ -98,6 +105,7 @@ bool RenderEngine::is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surf vkGetPhysicalDeviceFeatures(device, &device_features); try { + // Ловить исключения имеет смысыл только здесь QueueFamilyIndices indices = find_queue_family_indices(device, surface); } catch (...) { return false; @@ -155,8 +163,10 @@ RenderEngine::QueueFamilyIndices RenderEngine::find_queue_family_indices(VkPhysi // Find present VkBool32 present_support = false; VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue_family_indices.graphics_family.value(), surface, &present_support)); + // Если графическая очередь поддерживет презентацию кадров, то используем её if (present_support == VK_TRUE) queue_family_indices.present_family = queue_family_indices.graphics_family; + // иначе ищем другую подходящую очередь else { for(uint32_t i = 0; i < family_properties.size(); ++i) @@ -174,6 +184,8 @@ RenderEngine::QueueFamilyIndices RenderEngine::find_queue_family_indices(VkPhysi if (queue_family_indices.present_family.has_value() == false) throw std::runtime_error("Failed to find a present queue family"); + // С начала пытаемся найти очередь специалезированную + // для копирования отличную от графической for(uint32_t i = 0; i < family_properties.size(); ++i) { if (i == queue_family_indices.graphics_family.value()) @@ -181,6 +193,7 @@ RenderEngine::QueueFamilyIndices RenderEngine::find_queue_family_indices(VkPhysi if (family_properties[i].queueFlags & VK_QUEUE_TRANSFER_BIT) queue_family_indices.transfer_family = i; } + // Если не находим, то используем графическую if (queue_family_indices.transfer_family.has_value() == false) queue_family_indices.transfer_family = queue_family_indices.graphics_family; return queue_family_indices; @@ -208,6 +221,7 @@ VkPresentModeKHR RenderEngine::choose_present_mode(const std::vector::max()) return capabilities.currentExtent; else @@ -324,7 +338,7 @@ void RenderEngine::pick_physical_device() physical_device_ = device; VkPhysicalDeviceProperties device_properties; vkGetPhysicalDeviceProperties(physical_device_, &device_properties); - Log("Using device: " + std::string(device_properties.deviceName)); + Loging::Log("Using device: " + std::string(device_properties.deviceName)); break; } } @@ -705,7 +719,7 @@ void RenderEngine::allocate_vertex_buffer() VkBuffer staging_buffer = VK_NULL_HANDLE; VkDeviceMemory staging_buffer_memory = VK_NULL_HANDLE; - VkDeviceSize size_buffer = sizeof(vertices[0]) * vertices.size(); + VkDeviceSize size_buffer = sizeof(vertices_[0]) * vertices_.size(); create_buffer(size_buffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, &staging_buffer, transfer_index); allocate_memory(staging_buffer, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &staging_buffer_memory); @@ -717,7 +731,7 @@ void RenderEngine::allocate_vertex_buffer() void* data; VK_CHECK(vkMapMemory(device_, staging_buffer_memory, 0, size_buffer, 0, &data)); - memcpy(data, vertices.data(), size_buffer); + memcpy(data, vertices_.data(), size_buffer); vkUnmapMemory(device_, staging_buffer_memory); copy_memory(staging_buffer, vertex_buffer_, size_buffer); @@ -842,7 +856,7 @@ void RenderEngine::record_command_buffer(VkCommandBuffer command_buffer, uint32_ scissor.extent = swapchain_extent_; vkCmdSetScissor(command_buffer, 0, 1, &scissor); - vkCmdDraw(command_buffer, static_cast(vertices.size()), 1, 0, 0); + vkCmdDraw(command_buffer, static_cast(vertices_.size()), 1, 0, 0); vkCmdEndRenderPass(command_buffer); VK_CHECK(vkEndCommandBuffer(command_buffer)); @@ -972,14 +986,15 @@ RenderEngine::~RenderEngine() if (instance_ != VK_NULL_HANDLE) vkDestroyInstance(instance_, nullptr); - - if (window_ != nullptr) - glfwDestroyWindow(window_); - glfwTerminate(); } void RenderEngine::start() { + World* world = core_.GetGameInstance()->GetWorld(); + std::vector> meshes = world->GetActorsByClass(); + for (auto& i : meshes) + i->load_model(i->GetModelName()); + while (!glfwWindowShouldClose(window_)) { glfwPollEvents(); diff --git a/Core/Core/RenderEngine.h b/Core/Core/RenderEngine/RenderEngine.hpp similarity index 94% rename from Core/Core/RenderEngine.h rename to Core/Core/RenderEngine/RenderEngine.hpp index cdef903..9d47584 100644 --- a/Core/Core/RenderEngine.h +++ b/Core/Core/RenderEngine/RenderEngine.hpp @@ -8,9 +8,10 @@ #define GLFW_INCLUDE_VULKAN #include -#include #include +#include "ModelManager.hpp" + #ifdef _DEBUG #include #define VK_CHECK(res) assert(res == VK_SUCCESS) @@ -35,7 +36,6 @@ class RenderEngine std::vector present_modes; }; -#pragma region Experemental struct Vertex { glm::vec2 pos; @@ -43,24 +43,22 @@ class RenderEngine static VkVertexInputBindingDescription get_binding_description(); static std::array get_vertex_attribute_descriptions(); }; - std::vector vertices = { + std::vector vertices_ = { {{0.0f, -0.5f}, {1.0f, 0.0f, 0.0f}}, {{0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}}, {{-0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}} }; - VkBuffer vertex_buffer_ = VK_NULL_HANDLE; - VkDeviceMemory vertex_buffer_memory_ = VK_NULL_HANDLE; - uint32_t find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties) const; - void allocate_vertex_buffer(); - void copy_memory(VkBuffer src, VkBuffer dst, VkDeviceSize size); -#pragma endregion + ModelManager model_manager_; + static const std::vector deviceExtensions; int current_frame_ = 0; CoreInstance& core_; + GLFWwindow* window_; + VkInstance instance_ = VK_NULL_HANDLE; VkSurfaceKHR surface_ = VK_NULL_HANDLE; VkPhysicalDevice physical_device_ = VK_NULL_HANDLE; @@ -79,7 +77,10 @@ class RenderEngine std::vector framebuffers_; VkCommandPool command_pool_ = VK_NULL_HANDLE; std::vector command_buffers_; + VkBuffer vertex_buffer_ = VK_NULL_HANDLE; + VkDeviceMemory vertex_buffer_memory_ = VK_NULL_HANDLE; + // Sync objects std::vector image_available_semaphores_, render_finished_semaphores_; std::vector in_flight_fences_; @@ -100,6 +101,7 @@ class RenderEngine void create_buffer(VkDeviceSize size, VkBufferUsageFlags usage, VkBuffer* buffer, const std::vector& queue_families); void allocate_memory(VkBuffer buffer, VkMemoryPropertyFlags property, VkDeviceMemory* device_memory); + uint32_t find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties) const; void create_instance(); void create_surface(); @@ -113,6 +115,8 @@ class RenderEngine void create_command_pool(); void allocate_command_buffers(); void create_sync_objects(); + void allocate_vertex_buffer(); + void copy_memory(VkBuffer src, VkBuffer dst, VkDeviceSize size); void record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index) const; void draw_frame(); @@ -123,4 +127,9 @@ public: void start(); void stop_render() const; + + [[nodiscard]] + GLFWwindow* get_window() const { return window_; } + + ModelManager* GetActiveModelManager() { return &model_manager_; } }; \ No newline at end of file diff --git a/Core/Core/SystemCalls.h b/Core/Core/SystemCalls.h deleted file mode 100644 index 2a7f8e2..0000000 --- a/Core/Core/SystemCalls.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -class CoreInstance; - -struct CoreCallBacks; - -namespace System { - /** - * @throws std::exception if the operation finished with failed - * @return count CPU - */ - int getCountCPU(); - /* - * @throws std::runtime_error - * @return memory size in MB - */ - double getMemorySize(); - - /** - * Load module and init handler - * @throws std::runtime_error if module not found - * @return module handler - */ - void* InitModule(const char* ModuleName, CoreCallBacks* callbacks); - - /** - * Start module - * @throws std::runtime_error if module not contains StartModule function - */ - void StartModule(void* handler) noexcept(false); - - /** - * Call stop module - * @throws std::runtime_error if module not contains QuitModule function - */ - void QuitModule(void* handler) noexcept(false); -} diff --git a/Core/Core/SystemCalls.hpp b/Core/Core/SystemCalls.hpp new file mode 100644 index 0000000..aa56531 --- /dev/null +++ b/Core/Core/SystemCalls.hpp @@ -0,0 +1,14 @@ +#pragma once + +namespace System { + /** + * @throws std::exception if the operation finished with failed + * @return count CPU + */ + int getCountCPU(); + /* + * @throws std::runtime_error + * @return memory size in MB + */ + double getMemorySize(); +} diff --git a/Core/Core/Windows/WindowsCalls.cpp b/Core/Core/Windows/WindowsCalls.cpp index ad05a22..81824f4 100644 --- a/Core/Core/Windows/WindowsCalls.cpp +++ b/Core/Core/Windows/WindowsCalls.cpp @@ -1,6 +1,6 @@ #ifdef _WIN32 -#include "../SystemCalls.h" +#include "../SystemCalls.hpp" #include @@ -41,38 +41,4 @@ double System::getMemorySize() { return static_cast(memStatus.ullTotalPhys) / 1024. / 1024.; } -void* System::InitModule(const char* ModuleName, CoreCallBacks* callbacks) { - std::string fileName = ModuleName; - fileName += ".dll"; - - HMODULE hModule = LoadLibraryA(fileName.c_str()); - if(hModule == nullptr) - throw std::runtime_error(std::to_string(GetLastError()).c_str()); - - void(*load)(CoreCallBacks*) = reinterpret_cast(GetProcAddress(hModule, "InitModule")); - if(load == nullptr) { - throw std::runtime_error(std::to_string(GetLastError()).c_str()); - } - load(callbacks); - - return hModule; -} - -void System::StartModule(void* handler) { - void(*start)() = reinterpret_cast(GetProcAddress(static_cast(handler), "StartModule")); - if(start == nullptr) { - throw std::runtime_error(std::to_string(GetLastError()).c_str()); - } - start(); -} - -void System::QuitModule(void* handler) { - void(*quit)() = reinterpret_cast(GetProcAddress(static_cast(handler), "QuitModule")); - if(quit == nullptr) { - throw std::runtime_error(std::to_string(GetLastError()).c_str()); - } - quit(); - FreeLibrary(static_cast(handler)); -} - #endif \ No newline at end of file diff --git a/Core/Core/main.cpp b/Core/Core/main.cpp index e456cd3..be5bc25 100644 --- a/Core/Core/main.cpp +++ b/Core/Core/main.cpp @@ -1,10 +1,12 @@ #include -#include "CoreInstance.h" +#include "CoreInstance.hpp" int main(int argc, char* argv[]) { try { CoreInstance core; + if (core.IsReady() == false) + return 0; std::cout << "CPU: " << core.getCountCPU() << std::endl; std::cout << "Memory: " << core.getMemorySize() << std::endl; core.start(); diff --git a/Core/Game/Actors/Actor.cpp b/Core/Game/Actors/Actor.cpp index 99d7f43..14a7fe7 100644 --- a/Core/Game/Actors/Actor.cpp +++ b/Core/Game/Actors/Actor.cpp @@ -1,34 +1,37 @@ -#include "Actor.h" +#include "Actor.hpp" -#include "Game/SaveMap/SaveMap.h" -#include "Log/Log.h" +#include "Game/SaveMap/SaveMap.hpp" +#include "Game/World/World.hpp" +#include "Log/Log.hpp" -Actor::Actor() +void Actor::OnDestroy() +{ +} + +Actor::Actor() : loc_(new Vector3D), rot_(new Vector3D), scale_(new Vector3D) { SetType(Classes::Actor); } -std::shared_ptr Actor::save() noexcept +std::shared_ptr Actor::save() { - std::shared_ptr save = std::make_shared("Actor"); - save->SaveObject("loc", &loc) - ->SaveObject("rot", &rot) - ->SaveObject("scale", &scale) - ->SaveListStrings("tags", std::move(tags)); - return save; + return std::make_shared("Actor") + ->SaveObject("loc", static_cast>(loc_)) + ->SaveObject("rot", static_cast>(rot_)) + ->SaveObject("scale", UType::object_ptr(scale_)) + ->SaveListStrings("tags", std::move(tags)); } -void Actor::load(std::shared_ptr save) noexcept +void Actor::load(std::shared_ptr save) { - loc = *reinterpret_cast(save->GetObject("loc")); - rot = *reinterpret_cast(save->GetObject("rot")); - scale = *reinterpret_cast(save->GetObject("scale")); + loc_ = static_cast>(save->GetObject("loc")); + rot_ = static_cast>(save->GetObject("rot")); + scale_ = static_cast>(save->GetObject("scale")); tags = std::move(save->GetListString("tags")); } void Actor::BeginPlay() { - Log("Actor::BeginPlay"); } void Actor::Tick(double delta_time) @@ -37,13 +40,13 @@ void Actor::Tick(double delta_time) void Actor::SetActorLocate(const Vector3D& loc) noexcept { - this->loc = loc; + *this->loc_ = loc; OnSetActorLocate.Call(loc); } void Actor::SetActorRotate(const Vector3D& rot) noexcept { - this->rot = rot; + *this->rot_ = rot; OnSetActorRotate.Call(rot); } diff --git a/Core/Game/Actors/Actor.h b/Core/Game/Actors/Actor.hpp similarity index 63% rename from Core/Game/Actors/Actor.h rename to Core/Game/Actors/Actor.hpp index 6e5841b..2a4787f 100644 --- a/Core/Game/Actors/Actor.h +++ b/Core/Game/Actors/Actor.hpp @@ -6,17 +6,23 @@ #include "RTTI_Meta.h" #include "Game/SaveMap/ISave.h" #include "Delegate/Delegate.h" -#include "Math/Vector.h" +#include "Math/Vector.hpp" +#include "Types/object_ptr.hpp" +class World; GENERATE_META(Actor) class Actor : public ISave, public IRTTI { - Vector3D loc; - Vector3D rot; - Vector3D scale; + World* world_; + std::string name_; + + UType::object_ptr loc_, rot_, scale_; std::list tags; + +protected: + virtual void OnDestroy(); public: Actor(); @@ -24,8 +30,8 @@ public: Delegate OnSetActorRotate; #pragma region ISave - virtual std::shared_ptr save() noexcept override; - virtual void load(std::shared_ptr save) noexcept override; + std::shared_ptr save() override; + void load(std::shared_ptr save) override; #pragma endregion virtual void BeginPlay(); @@ -36,16 +42,21 @@ public: * Вызывает делегат OnSetActorLocate */ void SetActorLocate(const Vector3D& loc) noexcept; - inline const Vector3D& GetActorLocate() const { return loc; } + inline const UType::object_ptr GetActorLocate() const { return loc_; } /* * Изменяет ориентацию в пространстве * Вызывает делегат OnSetActorRotate */ void SetActorRotate(const Vector3D& rot) noexcept; - inline const Vector3D& GetActorRotate() const { return rot; } + inline const UType::object_ptr GetActorRotate() const { return rot_; } void AddTag(const std::string& tag) noexcept; void RemoveTag(const std::string& tag) noexcept; const std::list& GetTags() const { return tags; } + + World* GetWorld() const { return world_; } + const std::string& GetName() const { return name_; } + + friend class World; }; diff --git a/Core/Game/Actors/Mesh/Mesh.cpp b/Core/Game/Actors/Mesh/Mesh.cpp new file mode 100644 index 0000000..52c0f14 --- /dev/null +++ b/Core/Game/Actors/Mesh/Mesh.cpp @@ -0,0 +1,21 @@ +#include "Mesh.hpp" + +#include "Game/SaveMap/SaveMap.hpp" + +Mesh::Mesh() +{ + SetType(Classes::Mesh); +} + +std::shared_ptr Mesh::save() +{ + return std::make_shared("Mesh") + ->SaveString("model_name_", model_name_) + ->connect_to(Actor::save()); +} + +void Mesh::load(std::shared_ptr save) +{ + Actor::load(save->getParent()); + model_name_ = save->GetString("model_name_"); +} \ No newline at end of file diff --git a/Core/Game/Actors/Mesh/Mesh.hpp b/Core/Game/Actors/Mesh/Mesh.hpp new file mode 100644 index 0000000..7c0e65a --- /dev/null +++ b/Core/Game/Actors/Mesh/Mesh.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include "../Actor.hpp" + +GENERATE_META(Mesh) +class Mesh : public Actor +{ + std::string model_name_; +protected: + void SetModelName(const std::string& new_model_name) { model_name_ = new_model_name; } + +public: + Mesh(); + +#pragma region ISave + virtual std::shared_ptr save() override; + virtual void load(std::shared_ptr save) override; +#pragma endregion + + virtual void load_model(const std::string& model_name) = 0; + const std::string& GetModelName() const { return model_name_; } +}; diff --git a/Core/Game/Actors/Mesh/StaticMesh.cpp b/Core/Game/Actors/Mesh/StaticMesh.cpp new file mode 100644 index 0000000..86b8a4e --- /dev/null +++ b/Core/Game/Actors/Mesh/StaticMesh.cpp @@ -0,0 +1,36 @@ +#include "StaticMesh.hpp" + +#include "Core/CoreInstance.hpp" +#include "Core/RenderEngine/RenderEngine.hpp" +#include "Game/GameInstance.hpp" +#include "Log/Log.hpp" +#include "Game/SaveMap/SaveMap.hpp" +#include "Game/World/World.hpp" + +StaticMesh::StaticMesh() +{ + SetType(Classes::StaticMesh); +} + +std::shared_ptr StaticMesh::save() +{ + return std::make_shared("StaticMesh")->connect_to(Mesh::save()); +} + +void StaticMesh::load(std::shared_ptr save) +{ + Mesh::load(save->getParent()); +} + +void StaticMesh::load_model(const std::string& model_name) +{ + model_name_ = model_name; + SetModelName(model_name); + model_ = GetWorld()->GetGameInstance().GetCore().GetRenderEngine()->GetActiveModelManager()->LoadModel(model_name); +} + +void StaticMesh::OnDestroy() +{ + Mesh::OnDestroy(); + GetWorld()->GetGameInstance().GetCore().GetRenderEngine()->GetActiveModelManager()->FreeModel(model_name_); +} diff --git a/Core/Game/Actors/Mesh/StaticMesh.hpp b/Core/Game/Actors/Mesh/StaticMesh.hpp new file mode 100644 index 0000000..f3f2cb6 --- /dev/null +++ b/Core/Game/Actors/Mesh/StaticMesh.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "Mesh.hpp" +#include "Core/RenderEngine/ModelManager.hpp" + +GENERATE_META(StaticMesh) + +class StaticMesh : public Mesh +{ + std::string model_name_; + ModelManager::StaticModel* model_ = nullptr; +public: + StaticMesh(); + +#pragma region ISave + virtual std::shared_ptr save() override; + virtual void load(std::shared_ptr save) override; +#pragma endregion + + void load_model(const std::string& model_name) override; + void OnDestroy() override; +}; diff --git a/Core/Game/BaseObjectFactory.cpp b/Core/Game/BaseObjectFactory.cpp index 6edc75b..1b5418c 100644 --- a/Core/Game/BaseObjectFactory.cpp +++ b/Core/Game/BaseObjectFactory.cpp @@ -1,10 +1,12 @@ -#include "ObjectFactory.h" +#include "ObjectFactory.hpp" +#include "Actors/Mesh/StaticMesh.hpp" -#include "Game/Actors/Actor.h" -#include "Math/Vector.h" +#include "Game/Actors/Actor.hpp" +#include "Math/Vector.hpp" std::vector base_object_factories = { GENERATE_FACTORY_OBJECT(Actor) + GENERATE_FACTORY_OBJECT(StaticMesh) GENERATE_FACTORY_OBJECT(Vector2D) GENERATE_FACTORY_OBJECT(Vector3D) }; \ No newline at end of file diff --git a/Core/Game/GameInstance.cpp b/Core/Game/GameInstance.cpp index 43c5f37..abb70be 100644 --- a/Core/Game/GameInstance.cpp +++ b/Core/Game/GameInstance.cpp @@ -1,14 +1,14 @@ -#include "GameInstance.h" +#include "GameInstance.hpp" #include #include #include #include -#include "Core/CoreInstance.h" -#include "Game/WorldFactory.h" -#include "SaveMap/SaveMap.h" -#include "Game/World/World.h" +#include "Core/CoreInstance.hpp" +#include "Game/WorldFactory.hpp" +#include "SaveMap/SaveMap.hpp" +#include "Game/World/World.hpp" extern std::vector world_factories; @@ -19,13 +19,6 @@ GameInstance::GameInstance(CoreInstance& core) : core(core) // Init directories std::filesystem::create_directories(std::filesystem::path("./Resources")); - std::ifstream file("./Worlds/" + base_world + ".world"); - if (file.fail()) - throw std::runtime_error("Can't open world file"); - - std::string data; - std::getline(file, data); - for (auto& factories : world_factories) { if (factories.world_name == base_world) @@ -38,7 +31,6 @@ GameInstance::GameInstance(CoreInstance& core) : core(core) if (world == nullptr) throw std::runtime_error("Can't find world"); - world->load(std::make_shared(data)); } GameInstance::~GameInstance() diff --git a/Core/Game/GameInstance.h b/Core/Game/GameInstance.hpp similarity index 84% rename from Core/Game/GameInstance.h rename to Core/Game/GameInstance.hpp index 3da336a..8357518 100644 --- a/Core/Game/GameInstance.h +++ b/Core/Game/GameInstance.hpp @@ -17,8 +17,10 @@ class GameInstance std::atomic is_running = true; void start(); + // Stop call from core void stop(); public: + // Stop call from game void quit(); // Init vulkan @@ -26,6 +28,7 @@ public: virtual ~GameInstance(); World* GetWorld() const { return world; } + CoreInstance& GetCore() const { return core; } friend class CoreInstance; }; diff --git a/Core/Game/ObjectFactory.h b/Core/Game/ObjectFactory.hpp similarity index 100% rename from Core/Game/ObjectFactory.h rename to Core/Game/ObjectFactory.hpp diff --git a/Core/Game/Resource/IResource.h b/Core/Game/Resource/IResource.hpp similarity index 100% rename from Core/Game/Resource/IResource.h rename to Core/Game/Resource/IResource.hpp diff --git a/Core/Game/Resource/Resource.cpp b/Core/Game/Resource/Resource.cpp index e96bbb6..479db4b 100644 --- a/Core/Game/Resource/Resource.cpp +++ b/Core/Game/Resource/Resource.cpp @@ -1,4 +1,4 @@ -#include "Resource.h" +#include "Resource.hpp" #include #include diff --git a/Core/Game/Resource/Resource.h b/Core/Game/Resource/Resource.hpp similarity index 98% rename from Core/Game/Resource/Resource.h rename to Core/Game/Resource/Resource.hpp index 44d08e9..e719af1 100644 --- a/Core/Game/Resource/Resource.h +++ b/Core/Game/Resource/Resource.hpp @@ -1,6 +1,6 @@ #pragma once -#include "IResource.h" +#include "IResource.hpp" #include #include #include diff --git a/Core/Game/SaveMap/SaveMap.cpp b/Core/Game/SaveMap/SaveMap.cpp index 93f1417..ec18bf5 100644 --- a/Core/Game/SaveMap/SaveMap.cpp +++ b/Core/Game/SaveMap/SaveMap.cpp @@ -1,8 +1,8 @@ -#include "SaveMap.h" +#include "SaveMap.hpp" #include #include -#include "Game/ObjectFactory.h" +#include "Game/ObjectFactory.hpp" extern std::vector factories; extern std::vector base_object_factories; @@ -32,69 +32,72 @@ SaveMap::SaveMap(const char* class_name) : class_name(class_name) SaveMap::SaveMap(const std::string& json_data) { - for (size_t i = 0; i < json_data.length() - 1;) + std::string json_data_blank = CleaningJSON(json_data); + for (size_t i = 0; i < json_data_blank.length() - 1;) { - size_t key_begin = i = json_data.find_first_of('\"', i) + 1; - size_t key_end = i = json_data.find_first_of('\"', i); + size_t key_begin = i = json_data_blank.find_first_of('\"', i) + 1; + size_t key_end = i = json_data_blank.find_first_of('\"', i); + if (0 == key_begin) + return; - std::string name = json_data.substr(key_begin, key_end - key_begin); + std::string name = json_data_blank.substr(key_begin, key_end - key_begin); if (class_name.empty()) { - size_t begin = json_data.find(':', i) + 2; - size_t end = i = json_data.find('\"', begin); + size_t begin = json_data_blank.find(':', i) + 2; + size_t end = i = json_data_blank.find('\"', begin); i++; - class_name = json_data.substr(begin, end - begin); + class_name = json_data_blank.substr(begin, end - begin); continue; } if (name[0] == 'i') { - size_t begin = json_data.find(':', i) + 2; - size_t end = i = json_data.find_first_of(",}", i); + size_t begin = json_data_blank.find(':', i) + 1; + size_t end = i = json_data_blank.find_first_of(",}", i); i++; - std::string value = json_data.substr(begin, end - begin - 1); + std::string value = json_data_blank.substr(begin, end - begin); save_long[name.c_str() + 1] = std::stoll(value); } else if (name[0] == 'd') { - size_t begin = json_data.find(':', i) + 2; - size_t end = i = json_data.find_first_of(",}", i); + size_t begin = json_data_blank.find(':', i) + 1; + size_t end = i = json_data_blank.find_first_of(",}", i); i++; - std::string value = json_data.substr(begin, end - begin - 1); + std::string value = json_data_blank.substr(begin, end - begin); save_double[name.c_str() + 1] = std::stod(value); } else if (name[0] == 's') { - size_t begin = json_data.find(':', i) + 2; - size_t end = i = json_data.find('\"', begin); + size_t begin = json_data_blank.find(':', i) + 2; + size_t end = i = json_data_blank.find('\"', begin); i++; std::string value; if (begin != end) - value = json_data.substr(begin, end - begin); + value = json_data_blank.substr(begin, end - begin); else value = ""; save_string[name.c_str() + 1] = value; } else if (name[0] == 'o') { - size_t begin = i = json_data.find('{', i); + size_t begin = i = json_data_blank.find('{', i); int open = 1, close = 0; while (close < open) { i++; - if (json_data[i] == '{') + if (json_data_blank[i] == '{') open++; - else if (json_data[i] == '}') + else if (json_data_blank[i] == '}') close++; } size_t end = i; i++; - std::string object_json = json_data.substr(begin, end - begin + 1); + std::string object_json = json_data_blank.substr(begin, end - begin + 1); begin = object_json.find(':') + 2; end = object_json.find('\"', begin); std::string object_name = object_json.substr(begin, end - begin); - ISave* object_ptr = MakeObjectByName(object_name); + UType::object_ptr object_ptr(MakeObjectByName(object_name)); object_ptr->load(std::make_shared(object_json)); save_objects[name.c_str() + 1] = object_ptr; @@ -102,20 +105,20 @@ SaveMap::SaveMap(const std::string& json_data) { std::string key = name.substr(2, name.length() - 2); - size_t begin_arr = i = json_data.find('[', i); + size_t begin_arr = i = json_data_blank.find('[', i); int open = 1, close = 0; while (close < open) { i++; - if (json_data[i] == '[') + if (json_data_blank[i] == '[') open++; - else if (json_data[i] == ']') + else if (json_data_blank[i] == ']') close++; } size_t end_arr = i; i++; - std::string arr_data = json_data.substr(begin_arr, end_arr - begin_arr + 1); + std::string arr_data = json_data_blank.substr(begin_arr, end_arr - begin_arr + 1); if (name[1] == 'i') { save_vector_integer[key] = std::vector(); @@ -155,6 +158,8 @@ SaveMap::SaveMap(const std::string& json_data) while (j < arr_data.length()) { size_t begin = arr_data.find('\"', j) + 1; + if (begin == std::string::npos + 1) + break; size_t end = j = arr_data.find('\"', begin); std::string value; if (begin != end) @@ -162,14 +167,14 @@ SaveMap::SaveMap(const std::string& json_data) else value = ""; vector_strings.push_back(value); - j += 3; + ++j; } } else if (name[1] == 'o') { - save_vector_objects[key] = std::vector(); + save_vector_objects[key] = std::vector>(); if (arr_data.length() == 2) continue; - std::vector& vector_object = save_vector_objects[key]; + std::vector>& vector_object = save_vector_objects[key]; size_t j = 1; while (j < arr_data.length()) @@ -193,7 +198,7 @@ SaveMap::SaveMap(const std::string& json_data) size_t end_name = object_json.find('\"', begin_name); std::string object_name = object_json.substr(begin_name, end_name - begin_name); - ISave* object_ptr = MakeObjectByName(object_name); + UType::object_ptr object_ptr(MakeObjectByName(object_name)); object_ptr->load(std::make_shared(object_json)); vector_object.push_back(object_ptr); @@ -206,20 +211,20 @@ SaveMap::SaveMap(const std::string& json_data) { std::string key = name.substr(2, name.length() - 2); - size_t begin_arr = i = json_data.find('[', i); + size_t begin_arr = i = json_data_blank.find('[', i); int open = 1, close = 0; while (close < open) { i++; - if (json_data[i] == '[') + if (json_data_blank[i] == '[') open++; - else if (json_data[i] == ']') + else if (json_data_blank[i] == ']') close++; } size_t end_arr = i; i++; - std::string arr_data = json_data.substr(begin_arr, end_arr - begin_arr + 1); + std::string arr_data = json_data_blank.substr(begin_arr, end_arr - begin_arr + 1); if (name[1] == 'i') { save_list_integer[key] = std::list(); @@ -267,10 +272,10 @@ SaveMap::SaveMap(const std::string& json_data) } } else if (name[1] == 'o') { - save_list_objects[key] = std::list(); + save_list_objects[key] = std::list>(); if (arr_data.length() == 2) continue; - std::list& list_object = save_list_objects[key]; + std::list>& list_object = save_list_objects[key]; size_t j = 1; while (j < arr_data.length()) @@ -294,7 +299,7 @@ SaveMap::SaveMap(const std::string& json_data) size_t end_name = object_json.find('\"', begin_name); std::string object_name = object_json.substr(begin_name, end_name - begin_name); - ISave* object_ptr = MakeObjectByName(object_name); + UType::object_ptr object_ptr(MakeObjectByName(object_name)); object_ptr->load(std::make_shared(object_json)); list_object.push_back(object_ptr); @@ -304,21 +309,21 @@ SaveMap::SaveMap(const std::string& json_data) } } else if (name == "Parent parameters") { - size_t parent_begin = i = json_data.find('{', i); + size_t parent_begin = i = json_data_blank.find('{', i); int open = 1, close = 0; while (close < open) { i++; - if (json_data[i] == '{') + if (json_data_blank[i] == '{') open++; - else if (json_data[i] == '}') + else if (json_data_blank[i] == '}') close++; } size_t parent_end = i; i++; - std::string str = json_data.substr(parent_begin, parent_end - parent_begin + 1); + std::string str = json_data_blank.substr(parent_begin, parent_end - parent_begin + 1); parent_ = std::make_shared(str); } } @@ -384,7 +389,7 @@ std::shared_ptr SaveMap::SaveString(const char* name, const std::string return std::shared_ptr(this); } -std::shared_ptr SaveMap::SaveObject(const char* name, ISave* object) noexcept +std::shared_ptr SaveMap::SaveObject(const char* name, UType::object_ptr object) noexcept { save_objects[name] = object; return std::shared_ptr(this); @@ -408,7 +413,7 @@ std::shared_ptr SaveMap::SaveVectorStrings(const char* name, std::vecto return std::shared_ptr(this); } -std::shared_ptr SaveMap::SaveVectorObject(const char* name, std::vector&& value) noexcept +std::shared_ptr SaveMap::SaveVectorObject(const char* name, std::vector>&& value) noexcept { save_vector_objects[name] = std::move(value); return std::shared_ptr(this); @@ -432,7 +437,7 @@ std::shared_ptr SaveMap::SaveListStrings(const char* name, std::list(this); } -std::shared_ptr SaveMap::SaveListObject(const char* name, std::list&& value) noexcept +std::shared_ptr SaveMap::SaveListObject(const char* name, std::list>&& value) noexcept { save_list_objects[name] = std::move(value); return std::shared_ptr(this); @@ -448,12 +453,12 @@ double SaveMap::GetDouble(const char* name) return save_double[name]; } -const char* SaveMap::GetString(const char* name) +std::string SaveMap::GetString(const char* name) { - return save_string[name].c_str(); + return save_string[name]; } -ISave* SaveMap::GetObject(const char* name) +UType::object_ptr SaveMap::GetObject(const char* name) { return save_objects[name]; } @@ -473,7 +478,7 @@ std::vector SaveMap::GetVectorString(const char* name) return save_vector_strings[name]; } -std::vector& SaveMap::GetVectorObject(const char* name) +std::vector>& SaveMap::GetVectorObject(const char* name) { return save_vector_objects[name]; } @@ -493,7 +498,7 @@ std::list& SaveMap::GetListString(const char* name) return save_list_strings[name]; } -std::list& SaveMap::GetListObject(const char* name) +std::list>& SaveMap::GetListObject(const char* name) { return save_list_objects[name]; } @@ -626,11 +631,28 @@ std::string SaveMap::serialize() noexcept return buffer; } -SaveMap* SaveMap::connect_to(const std::shared_ptr& parent) +std::shared_ptr SaveMap::connect_to(const std::shared_ptr& parent) { if (this->parent_ != nullptr) throw std::runtime_error("Can't connect to second parent"); this->parent_ = parent; - return this; + return std::shared_ptr(this); +} + +std::string SaveMap::CleaningJSON(const std::string& json_data) +{ + std::string blank_str; + blank_str.reserve(json_data.length()); + + bool open_str = false; + for (auto i : json_data) + { + if (i == '\"') + open_str = !open_str; + if (open_str || (i != ' ' && i != '\t' && i != '\n' && i != '\r')) + blank_str += i; + } + + return blank_str; } diff --git a/Core/Game/SaveMap/SaveMap.h b/Core/Game/SaveMap/SaveMap.hpp similarity index 61% rename from Core/Game/SaveMap/SaveMap.h rename to Core/Game/SaveMap/SaveMap.hpp index 7e6de79..d3d2549 100644 --- a/Core/Game/SaveMap/SaveMap.h +++ b/Core/Game/SaveMap/SaveMap.hpp @@ -1,8 +1,9 @@ #pragma once #include "ISave.h" +#include "Types/object_ptr.hpp" -#include +#include #include #include #include @@ -14,22 +15,22 @@ class SaveMap final std::shared_ptr parent_; // Индивидуальные значения - std::map save_long; - std::map save_double; - std::map save_string; - std::map save_objects; + std::unordered_map save_long; + std::unordered_map save_double; + std::unordered_map save_string; + std::unordered_map> save_objects; // Массивы - std::map> save_vector_integer; - std::map> save_vector_double; - std::map> save_vector_objects; - std::map> save_vector_strings; + std::unordered_map> save_vector_integer; + std::unordered_map> save_vector_double; + std::unordered_map>> save_vector_objects; + std::unordered_map> save_vector_strings; // Связаные списки - std::map> save_list_integer; - std::map> save_list_double; - std::map> save_list_objects; - std::map> save_list_strings; + std::unordered_map> save_list_integer; + std::unordered_map> save_list_double; + std::unordered_map>> save_list_objects; + std::unordered_map> save_list_strings; static ISave* MakeObjectByName(const std::string& name); @@ -47,29 +48,29 @@ public: std::shared_ptr SaveInteger(const char* name, int value) noexcept; std::shared_ptr SaveDouble(const char* name, double value) noexcept; std::shared_ptr SaveString(const char* name, const std::string& value) noexcept; - std::shared_ptr SaveObject(const char* name, ISave* object) noexcept; + std::shared_ptr SaveObject(const char* name, UType::object_ptr object) noexcept; std::shared_ptr SaveVectorInteger(const char* name, std::vector&& value) noexcept; std::shared_ptr SaveVectorDouble(const char* name, std::vector&& value) noexcept; std::shared_ptr SaveVectorStrings(const char* name, std::vector&& value) noexcept; - std::shared_ptr SaveVectorObject(const char* name, std::vector&& value) noexcept; + std::shared_ptr SaveVectorObject(const char* name, std::vector>&& value) noexcept; std::shared_ptr SaveListInteger(const char* name, std::list&& value) noexcept; std::shared_ptr SaveListDouble(const char* name, std::list&& value) noexcept; std::shared_ptr SaveListStrings(const char* name, std::list&& value) noexcept; - std::shared_ptr SaveListObject(const char* name, std::list&& value) noexcept; + std::shared_ptr SaveListObject(const char* name, std::list>&& value) noexcept; // Методы получения значенй long long GetInteger(const char* name); double GetDouble(const char* name); - const char* GetString(const char* name); - ISave* GetObject(const char* name); + std::string GetString(const char* name); + UType::object_ptr GetObject(const char* name); std::vector& GetVectorInteger(const char* name); std::vector& GetVectorDouble(const char* name); std::vector GetVectorString(const char* name); - std::vector& GetVectorObject(const char* name); + std::vector>& GetVectorObject(const char* name); std::list& GetListInteger(const char* name); std::list& GetListDouble(const char* name); std::list& GetListString(const char* name); - std::list& GetListObject(const char* name); + std::list>& GetListObject(const char* name); std::shared_ptr getParent() const { return parent_; } const std::string& getClassName() const { return class_name; } @@ -77,5 +78,7 @@ public: // Собирает все токены в JSON объект std::string serialize() noexcept; - SaveMap* connect_to(const std::shared_ptr& parent); + std::shared_ptr connect_to(const std::shared_ptr& parent); + + static std::string CleaningJSON(const std::string& json_data); }; diff --git a/Core/Game/World/World.cpp b/Core/Game/World/World.cpp index 591b539..694d925 100644 --- a/Core/Game/World/World.cpp +++ b/Core/Game/World/World.cpp @@ -1,6 +1,6 @@ -#include "World.h" +#include "World.hpp" -#include "Game/SaveMap/SaveMap.h" +#include "Game/SaveMap/SaveMap.hpp" World::World(GameInstance& game_instance) : game_instance(game_instance) { @@ -8,31 +8,51 @@ World::World(GameInstance& game_instance) : game_instance(game_instance) World::~World() { - for (auto& actor : actors) - delete actor; - actors.clear(); + for (auto& i : actors_map) + i.second->OnDestroy(); + actors_map.clear(); } void World::BeginPlay() { - for (auto& i : actors) - i->BeginPlay(); + for (auto& i : actors_map) + i.second->BeginPlay(); } void World::Tick(double delta_time) { - for (auto& i : actors) - i->Tick(delta_time); + for (auto& i : actors_map) + i.second->Tick(delta_time); } std::shared_ptr World::save() { std::shared_ptr save = std::make_shared("World"); - save->SaveListObject("Actors", std::move(reinterpret_cast&>(actors))); return save; } void World::load(std::shared_ptr save) { - actors = std::move(reinterpret_cast&>(save->GetListObject("Actors"))); -} \ No newline at end of file + std::vector actors_IDs = save->GetVectorString("ActorsIDs"); + std::list> act = std::move(reinterpret_cast>&>(save->GetListObject("Actors"))); + + size_t i_id = 0; + for (auto& i : act) + { + auto[it, flag] = actors_map.try_emplace(actors_IDs[i_id], i); + it->second->world_ = this; + it->second->name_ = it->first; + i_id++; + } +} + +void World::DestroyActor(UType::object_ptr ptr) +{ + if (ptr.get() == nullptr) + return; + + std::string name = ptr->GetName(); + actors_map.erase(name); + ptr->OnDestroy(); + ptr.destroy(); +} diff --git a/Core/Game/World/World.h b/Core/Game/World/World.h deleted file mode 100644 index 1b5f402..0000000 --- a/Core/Game/World/World.h +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "RTTI.h" -#include "Game/Actors/Actor.h" - -class GameInstance; - -class World : public ISave -{ - GameInstance& game_instance; - - // Actors only - std::list actors; - -public: - World(GameInstance& game_instance); - ~World() override; - - virtual void BeginPlay(); - virtual void Tick(double delta_time); - - GameInstance& GetGameInstance() const { return game_instance; } - -#pragma region ISave - std::shared_ptr save() override; - void load(std::shared_ptr save) override; -#pragma endregion - - template> - Container GetActorsByClass() - { - Container list; - for (auto i = actors.cbegin(); i != actors.cend(); ++i) - { - if (RTTI::IsA(*i)) - list.push_back(*i); - } - return list; - } - - template - T* SpawnActorFormClass(const Vector3D& loc = { 0, 0, 0 }, const Vector3D& rot = { 0, 0, 0 }) - { - T* object = new T(); - object->SetActorLocate(loc); - object->SetActorRotate(rot); - actors.push_back(object); - return object; - } - - template> - Container GetActorsByTag(std::string tag) - { - Container container; - - for (auto& i : actors) - { - const std::list& tags = i->GetTags(); - for (auto& j : tags) - { - if (j == tag) - container.push_back(i); - } - } - - return container; - } -}; - diff --git a/Core/Game/World/World.hpp b/Core/Game/World/World.hpp new file mode 100644 index 0000000..dfeef07 --- /dev/null +++ b/Core/Game/World/World.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include +#include +#include +#include + +#include "RTTI.h" +#include "Game/Actors/Actor.hpp" +#include "Game/Actors/Mesh/Mesh.hpp" +#include "Types/object_ptr.hpp" + +class GameInstance; + +GENERATE_META(World); +class World : public ISave +{ + GameInstance& game_instance; + + std::unordered_map> actors_map; + +public: + World(GameInstance& game_instance); + ~World() override; + + virtual void BeginPlay(); + virtual void Tick(double delta_time); + + GameInstance& GetGameInstance() const { return game_instance; } + +#pragma region ISave + std::shared_ptr save() override; + void load(std::shared_ptr save) override; +#pragma endregion + + template + std::vector> GetActorsByClass() + { + std::vector> list; + for (auto i = actors_map.cbegin(); i != actors_map.cend(); ++i) + { + if (T* cast_object = RTTI::dyn_cast(i->second.get())) + list.push_back(UType::object_ptr(cast_object)); + } + return list; + } + + template + UType::object_ptr SpawnActorFormClass(std::string name, const Vector3D& loc = { 0, 0, 0 }, const Vector3D& rot = { 0, 0, 0 }) + { + UType::object_ptr object(new T()); + object->SetActorLocate(loc); + object->SetActorRotate(rot); + static_cast(object)->world_ = this; + actors_map.try_emplace(name, object); + return object; + } + + void DestroyActor(UType::object_ptr ptr); + + template> + Container GetActorsByTag(std::string tag) + { + Container container; + + for (auto& i : actors_map) + { + const std::list& tags = i.second->GetTags(); + for (auto& j : tags) + { + if (j == tag) + container.push_back(i); + } + } + + return container; + } + + template + UType::object_ptr GetActorByID(const std::string& id) + { + return actors_map[id]; + } +}; + diff --git a/Core/Game/WorldFactory.h b/Core/Game/WorldFactory.hpp similarity index 52% rename from Core/Game/WorldFactory.h rename to Core/Game/WorldFactory.hpp index 9f29920..d9ac6d0 100644 --- a/Core/Game/WorldFactory.h +++ b/Core/Game/WorldFactory.hpp @@ -1,6 +1,9 @@ #pragma once #include +#include +#include +#include "Game/SaveMap/SaveMap.hpp" class GameInstance; class World; @@ -16,7 +19,21 @@ struct WorldFactory #define WORLDS_LIST std::vector world_factories = // Генерирует элемент списка -#define GENERATE_WORLD_FACTORY(Class, WorldName) WorldFactory{#WorldName, [](GameInstance& game_insance)->World* { return new Class(game_insance); }}, +#define GENERATE_WORLD_FACTORY(Class, WorldName) WorldFactory{#WorldName,\ +[](GameInstance& game_insance)->World* {\ + Class* world = new Class(game_insance);\ + std::ifstream config_file("./Worlds/" #WorldName ".world");\ + if (config_file.fail())\ + throw std::runtime_error("Can't open world file");\ + config_file.seekg(0, std::ios::end);\ + size_t file_size = config_file.tellg();\ + config_file.seekg(0, std::ios::beg);\ + std::string data;\ + data.resize(file_size);\ + config_file.read(data.data(), file_size);\ + world->load(std::make_shared(data));\ + return world;\ +}}, /* * Пример использования: diff --git a/Core/Log/Log.cpp b/Core/Log/Log.cpp index 2b0c4e7..184acc4 100644 --- a/Core/Log/Log.cpp +++ b/Core/Log/Log.cpp @@ -1,39 +1,39 @@ -#include "Log.h" +#include "Log.hpp" #include #include -std::mutex mOutput; +static std::mutex mOutput; #ifdef _DEBUG -void Log(const char* msg) +void Loging::Log(const char* msg) { std::lock_guard lock(mOutput); std::cout << msg << '\n'; } -void Log(const std::string& msg) +void Loging::Log(const std::string& msg) { std::lock_guard lock(mOutput); std::cout << msg << '\n'; } #else -void Log(const char* msg) +void Loging::Log(const char* msg) { } -void Log(const std::string& msg) +void Loging::Log(const std::string& msg) { } #endif -void Message(const char* msg) +void Loging::Message(const char* msg) { std::lock_guard lock(mOutput); std::cout << msg << '\n'; } -void Message(const std::string& msg) +void Loging::Message(const std::string& msg) { std::lock_guard lock(mOutput); std::cout << msg << '\n'; diff --git a/Core/Log/Log.h b/Core/Log/Log.h deleted file mode 100644 index 8027a10..0000000 --- a/Core/Log/Log.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include - -void Log(const char* msg); -void Log(const std::string& msg); - -void Message(const char* msg); -void Message(const std::string& msg); \ No newline at end of file diff --git a/Core/Log/Log.hpp b/Core/Log/Log.hpp new file mode 100644 index 0000000..3ba073c --- /dev/null +++ b/Core/Log/Log.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace Loging +{ + void Log(const char* msg); + void Log(const std::string& msg); + + void Message(const char* msg); + void Message(const std::string& msg); +} diff --git a/Core/Math/Vector.cpp b/Core/Math/Vector.cpp index bac260a..a86d94b 100644 --- a/Core/Math/Vector.cpp +++ b/Core/Math/Vector.cpp @@ -1,6 +1,6 @@ -#include "Vector.h" +#include "Vector.hpp" -#include "Game/SaveMap/SaveMap.h" +#include "Game/SaveMap/SaveMap.hpp" Vector2D::Vector2D(const double x, const double y) : x(x), y(y) {} diff --git a/Core/Math/Vector.h b/Core/Math/Vector.hpp similarity index 100% rename from Core/Math/Vector.h rename to Core/Math/Vector.hpp diff --git a/Core/Types/object_ptr.cpp b/Core/Types/object_ptr.cpp new file mode 100644 index 0000000..eb83a39 --- /dev/null +++ b/Core/Types/object_ptr.cpp @@ -0,0 +1,3 @@ +#include "object_ptr.hpp" + +std::unordered_map UType::counter::owners_map; \ No newline at end of file diff --git a/Core/Types/object_ptr.hpp b/Core/Types/object_ptr.hpp new file mode 100644 index 0000000..3b8414b --- /dev/null +++ b/Core/Types/object_ptr.hpp @@ -0,0 +1,175 @@ + +#pragma once + +#include +#include +#include + +namespace UType +{ + template + class object_ptr; + + class counter + { + struct counter_owners + { + std::atomic_bool is_destroyed; + std::mutex mutex; + std::list owners; + + counter_owners() + : is_destroyed(false) + { + } + + counter_owners(const counter_owners&) = delete; + counter_owners& operator=(const counter_owners&) = delete; + + counter_owners(counter_owners&& other) noexcept + : is_destroyed(other.is_destroyed.load()) + , owners(std::move(other.owners)) + { + } + + counter_owners& operator=(counter_owners&& other) noexcept + { + if (this != &other) + { + is_destroyed.store(other.is_destroyed.load()); + owners = std::move(other.owners); + } + return *this; + } + }; + static std::unordered_map owners_map; + + public: + template +static void add_owner(object_ptr& ptr) + { + auto counter = owners_map.find(ptr.ptr_.load()); + if (counter == owners_map.end()) + { + counter_owners owners; + owners.owners.push_back(&ptr); + auto [it, inserted] = owners_map.try_emplace(ptr.ptr_.load(), std::move(owners)); + if (!inserted) + { + ptr.ptr_.store(nullptr); + } + } + else if (!counter->second.is_destroyed) + { + std::lock_guard lock(counter->second.mutex); + counter->second.owners.push_back(&ptr); + } + else + ptr.ptr_.store(nullptr); + } + + template + static void remove_owner(object_ptr& ptr) + { + auto counter = owners_map.find(ptr.ptr_); + if (counter != owners_map.end()) + { + counter->second.owners.remove(&ptr); + + if (counter->second.is_destroyed) + { + ptr.ptr_.store(nullptr); + } + else if (counter->second.owners.empty()) + { + counter->second.is_destroyed.store(true); + for (auto& owner : counter->second.owners) + static_cast*>(owner)->ptr_.store(nullptr); + delete static_cast(counter->first); + owners_map.erase(counter); + } + } + } + + template + static void remove_object(Ty* ptr) + { + auto counter = owners_map.find(ptr); + if (counter != owners_map.end()) + { + counter->second.is_destroyed.store(true); + for (auto& owner : counter->second.owners) + static_cast*>(owner)->ptr_.store(nullptr); + delete ptr; + owners_map.erase(counter); + } + } + }; + + template + class object_ptr + { + std::atomic ptr_; + public: + explicit object_ptr(Ty* ptr = nullptr) + { + ptr_.store(ptr); + if (ptr) counter::add_owner(*this); + } + + object_ptr(const object_ptr& ptr) + { + ptr_.store(ptr.ptr_); + if (ptr.ptr_) counter::add_owner(*this); + } + + object_ptr(object_ptr&& ptr) noexcept + { + ptr_.store(ptr.ptr_); + if (ptr.ptr_) counter::add_owner(*this); + ptr.ptr_.store(nullptr); + } + + ~object_ptr() + { + if (ptr_) counter::remove_owner(*this); + } + + void reset(Ty* new_ptr = nullptr) + { + if (ptr_) counter::remove_owner(*this); + ptr_.store(new_ptr); + if (new_ptr) counter::add_owner(*this); + } + + void reset(const object_ptr& ptr) + { + if (ptr_) counter::remove_owner(*this); + ptr_.store(ptr.ptr_); + if (ptr.ptr_) counter::add_owner(*this); + } + + void destroy() + { + if (ptr_) counter::remove_object(ptr_); + } + + Ty* get() const noexcept { return ptr_.load(); } + Ty& operator*() const noexcept { return *ptr_; } + Ty* operator->() const noexcept { return ptr_.load(); } + operator bool() const noexcept { return ptr_.load() != nullptr; } + object_ptr& operator=(const object_ptr& ptr) + { + reset(ptr); + return *this; + } + + template + explicit operator object_ptr() const noexcept + { + return object_ptr(reinterpret_cast(ptr_.load())); + } + + friend class counter; + }; +} \ No newline at end of file diff --git a/FastRTTI/RTTI_Meta.h b/FastRTTI/RTTI_Meta.h index a222b70..d348cee 100644 --- a/FastRTTI/RTTI_Meta.h +++ b/FastRTTI/RTTI_Meta.h @@ -13,5 +13,5 @@ template struct Meta; // Enum type classes enum class Classes { - IRTTI, IResource, Actor, TestActor + IRTTI, IResource, Actor, TestActor, Mesh, StaticMesh, World, TestWorld }; diff --git a/ModuleLib/CMakeLists.txt b/ModuleLib/CMakeLists.txt deleted file mode 100644 index 37f27f8..0000000 --- a/ModuleLib/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -set(MODULE_LIB_NAME ModuleLib) - -file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp") - -add_library(${MODULE_LIB_NAME} STATIC ${SRC}) - -target_include_directories(${MODULE_LIB_NAME} PRIVATE - ${PROJECT_SOURCE_DIR}/Core - ${PROJECT_SOURCE_DIR}/Delegate -) - -if(UNIX AND NOT APPLE) - target_compile_options(${MODULE_LIB_NAME} PRIVATE -fPIC) -endif() diff --git a/ModuleLib/ModuleInstance.cpp b/ModuleLib/ModuleInstance.cpp deleted file mode 100644 index 0de6931..0000000 --- a/ModuleLib/ModuleInstance.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "ModuleInstance.h" - -#include -#include - -#include "Core/CoreCallBacks.h" - -extern ModuleInstance* Factory(); - -static std::mutex mModuleInstance; -static ModuleInstance* module = nullptr; -static std::thread* moduleThread; -// Don't free. It's memory free in core -static CoreCallBacks* callbacks_; - -void ModuleInstance::start() -{ -} - -void ModuleInstance::stop() -{ - onStop.Call(); -} - -void ModuleInstance::QuitGame() -{ - callbacks_->Quit(); -} - -void InitModule(CoreCallBacks* callbacks) -{ - std::lock_guard lock(mModuleInstance); - callbacks_ = callbacks; - if(module == nullptr) - module = Factory(); -} - -void StartModule() -{ - std::lock_guard lock(mModuleInstance); - if (module != nullptr) - moduleThread = new std::thread(&ModuleInstance::start, module); -} - -void QuitModule() -{ - std::lock_guard lock(mModuleInstance); - if(module != nullptr) - { - module->stop(); - moduleThread->join(); - delete module; - module = nullptr; - delete moduleThread; - moduleThread = nullptr; - } -} diff --git a/ModuleLib/ModuleInstance.h b/ModuleLib/ModuleInstance.h deleted file mode 100644 index fc53ca6..0000000 --- a/ModuleLib/ModuleInstance.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "Delegate/Delegate.h" - -#ifdef _WIN32 -#define EXPORT __declspec(dllexport) -#elif __linux__ -#define EXPORT -#else -#error message("Unknow platform") -#endif -/* -* This macro protects -* module callbacks from GB -*/ -#define PROTECTION_FROM_GB(Class) \ -extern "C" {\ -EXPORT void* protect_init() {return reinterpret_cast(&InitModule);} \ -EXPORT void* protect_start() {return reinterpret_cast(&StartModule);} \ -EXPORT void* protect_quit() {return reinterpret_cast(&QuitModule);} \ -}\ -ModuleInstance* Factory() { return static_cast(new Class()); } - -struct CoreCallBacks; - -class ModuleInstance { -public: - Delegate onStop; - - virtual ~ModuleInstance() = default; - - virtual void start(); - void stop(); - - void QuitGame(); -}; - -extern "C" { - // Create module instance - EXPORT void InitModule(CoreCallBacks* callbacks); - - // Start module instance - EXPORT void StartModule(); - - // Stop module when core calls this - EXPORT void QuitModule(); -} diff --git a/TestGame/Worlds/TestWorld.world b/TestGame/Worlds/TestWorld.world index 7bdcf01..0a5e7f2 100644 --- a/TestGame/Worlds/TestWorld.world +++ b/TestGame/Worlds/TestWorld.world @@ -1 +1,68 @@ -{"Class name":"TestWorld","dtime":5.000000,"Parent parameters":{"Class name":"World","loActors":[]}} \ No newline at end of file +{ + "Class name": "TestWorld", + "dtime": 5.000000, + "Parent parameters": { + "Class name":"World", + "vsActorsIDs": ["TestMesh1","TestMesh2"], + "loActors": [ + { + "Class name": "StaticMesh", + "Parent parameters": { + "Class name": "Mesh", + "smodel_name_": "TestModel", + "Parent parameters": { + "Class name":"Actor", + "oloc": { + "Class name":"Vector3D", + "dx":1.0, + "dy":-1.0, + "dz":1.0 + }, + "orot": { + "Class name":"Vector3D", + "dx":0.0, + "dy":0.0, + "dz":0.0 + }, + "oscale": { + "Class name": "Vector3D", + "dx": 1.0, + "dy": 1.0, + "dz": 1.0 + }, + "tags":[] + } + } + }, + { + "Class name": "StaticMesh", + "Parent parameters": { + "Class name": "Mesh", + "smodel_name_": "TestModel", + "Parent parameters": { + "Class name":"Actor", + "oloc": { + "Class name":"Vector3D", + "dx":0.0, + "dy":-1.0, + "dz":1.0 + }, + "orot": { + "Class name":"Vector3D", + "dx":0.0, + "dy":0.0, + "dz":0.0 + }, + "oscale": { + "Class name": "Vector3D", + "dx": 1.0, + "dy": 1.0, + "dz": 1.0 + }, + "tags":[] + } + } + } + ] + } +} \ No newline at end of file diff --git a/TestGame/main_config.conf b/TestGame/main_config.conf index a51e392..9f00330 100644 --- a/TestGame/main_config.conf +++ b/TestGame/main_config.conf @@ -1 +1,7 @@ -{"Class name":"MainConfig","dmin_memory_size":"4096.0","imin_CPU_count":"1","sgame_name":"Test Game","sbase_world":"TestWorld","vsmodules_names":[]} \ No newline at end of file +{ + "Class name": "MainConfig", + "dmin_memory_size": 4096.0, + "imin_CPU_count": 1, + "sgame_name": "Test Game", + "sbase_world": "TestWorld" +} \ No newline at end of file diff --git a/TestGame/src/Actors/TestActor.cpp b/TestGame/src/Actors/TestActor.cpp index da903e9..c5fe540 100644 --- a/TestGame/src/Actors/TestActor.cpp +++ b/TestGame/src/Actors/TestActor.cpp @@ -1,9 +1,9 @@ #include "TestActor.h" -#include "Log/Log.h" +#include "Log/Log.hpp" void TestActor::BeginPlay() { Actor::BeginPlay(); - Log("TestActor::BeginPlay"); + Loging::Log("TestActor::BeginPlay"); } \ No newline at end of file diff --git a/TestGame/src/Actors/TestActor.h b/TestGame/src/Actors/TestActor.h index ebecad9..b27b1b0 100644 --- a/TestGame/src/Actors/TestActor.h +++ b/TestGame/src/Actors/TestActor.h @@ -1,6 +1,6 @@ #pragma once -#include "Game/Actors/Actor.h" +#include "Game/Actors/Actor.hpp" GENERATE_META(TestActor) class TestActor final : public Actor diff --git a/TestGame/src/Factories/ObjectFactory.cpp b/TestGame/src/Factories/ObjectFactory.cpp index 4690e4b..0c8baf5 100644 --- a/TestGame/src/Factories/ObjectFactory.cpp +++ b/TestGame/src/Factories/ObjectFactory.cpp @@ -1,4 +1,4 @@ -#include "Game/ObjectFactory.h" +#include "Game/ObjectFactory.hpp" #include "../Actors/TestActor.h" diff --git a/TestGame/src/Factories/WorldFactory.cpp b/TestGame/src/Factories/WorldFactory.cpp index 74185dd..b44b49d 100644 --- a/TestGame/src/Factories/WorldFactory.cpp +++ b/TestGame/src/Factories/WorldFactory.cpp @@ -1,4 +1,4 @@ -#include "Game/WorldFactory.h" +#include "Game/WorldFactory.hpp" #include "../Worlds/TestWorld.h" diff --git a/TestGame/src/TestGameInstance.cpp b/TestGame/src/TestGameInstance.cpp index fe4677e..e062916 100644 --- a/TestGame/src/TestGameInstance.cpp +++ b/TestGame/src/TestGameInstance.cpp @@ -1,10 +1,10 @@ #include "TestGameInstance.h" -#include "Game/Resource/Resource.h" +#include "Game/Resource/Resource.hpp" #include -#include "Game/SaveMap/SaveMap.h" -#include "Game/World/World.h" +#include "Game/SaveMap/SaveMap.hpp" +#include "Game/World/World.hpp" GENERATE_FACTORY_GAME_INSTANCE(TestGameInstance) TestGameInstance::TestGameInstance(CoreInstance& core) : GameInstance(core) diff --git a/TestGame/src/TestGameInstance.h b/TestGame/src/TestGameInstance.h index 15f50f6..e68e9f5 100644 --- a/TestGame/src/TestGameInstance.h +++ b/TestGame/src/TestGameInstance.h @@ -1,6 +1,6 @@ #pragma once -#include "Game/GameInstance.h" +#include "Game/GameInstance.hpp" class TestGameInstance : public GameInstance { diff --git a/TestGame/src/Worlds/TestWorld.cpp b/TestGame/src/Worlds/TestWorld.cpp index b40064b..fe65334 100644 --- a/TestGame/src/Worlds/TestWorld.cpp +++ b/TestGame/src/Worlds/TestWorld.cpp @@ -1,8 +1,8 @@ #include "TestWorld.h" -#include "Game/GameInstance.h" -#include "Game/SaveMap/SaveMap.h" -#include "Log/Log.h" +#include "Game/GameInstance.hpp" +#include "Game/SaveMap/SaveMap.hpp" +#include "Log/Log.hpp" TestWorld::TestWorld(GameInstance& game_instance) : World(game_instance) {} @@ -10,7 +10,9 @@ TestWorld::TestWorld(GameInstance& game_instance) : World(game_instance) void TestWorld::BeginPlay() { World::BeginPlay(); - Log("TestWorld::BeginPlay"); + std::vector> meshes = GetActorsByClass(); + for (const auto& i : meshes) + Loging::Log("Load actor: " + i->GetName()); } void TestWorld::Tick(double delta_time) @@ -20,7 +22,15 @@ void TestWorld::Tick(double delta_time) time += delta_time; if (time >= 10.0) { - Message("TestWorld: Time out"); + std::vector> meshes = GetActorsByClass(); + if (!meshes.empty()) + { + Loging::Message("TestWorld destroy: " + meshes[0]->GetName()); + DestroyActor(static_cast>(meshes[0])); + time = 7.0; + return; + } + Loging::Message("TestWorld: Time out"); GetGameInstance().quit(); } } diff --git a/TestGame/src/Worlds/TestWorld.h b/TestGame/src/Worlds/TestWorld.h index 1e6081b..a54a1c1 100644 --- a/TestGame/src/Worlds/TestWorld.h +++ b/TestGame/src/Worlds/TestWorld.h @@ -1,7 +1,8 @@ #pragma once -#include "Game/World/World.h" +#include "Game/World/World.hpp" +GENERATE_META(TestWorld) class TestWorld final : public World { double time = 0; diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt new file mode 100644 index 0000000..696181f --- /dev/null +++ b/Tests/CMakeLists.txt @@ -0,0 +1,31 @@ +set(CMAKE_CXX_STANDARD 17) +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/refs/tags/v1.15.0.zip + DOWNLOAD_EXTRACT_TIMESTAMP true +) +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +enable_testing() + +file(GLOB SRC + "SaveMapTest.cpp" + "ObjectPtrTest.cpp" + + "${PROJECT_SOURCE_DIR}/Core/Game/SaveMap/SaveMap.cpp" + "${PROJECT_SOURCE_DIR}/Core/Types/object_ptr.cpp" +) + +add_executable(Tests ${SRC}) +target_link_libraries(Tests PRIVATE + GTest::gtest_main +) +target_include_directories(Tests PRIVATE + ${PROJECT_SOURCE_DIR}/Core +) + + +include(GoogleTest) +gtest_discover_tests(Tests) \ No newline at end of file diff --git a/Tests/ObjectPtrTest.cpp b/Tests/ObjectPtrTest.cpp new file mode 100644 index 0000000..d6704fc --- /dev/null +++ b/Tests/ObjectPtrTest.cpp @@ -0,0 +1,59 @@ +#include +#include "Types/object_ptr.hpp" + +class TestClass +{ + int* test_ptr_; +public: + TestClass(int* test_ptr) : test_ptr_(test_ptr) + { + *test_ptr_ = 1; + } + + ~TestClass() + { + *test_ptr_ = 2; + } +}; + +TEST(object_ptr_test, base_test) +{ + int* test = new int(123); + UType::object_ptr ptr(test); + EXPECT_EQ(*ptr.get(), 123); + + UType::object_ptr ptr2(ptr); + EXPECT_EQ(*ptr2.get(), 123); + EXPECT_EQ(ptr2.get(), ptr.get()); + + ptr.destroy(); + EXPECT_EQ(ptr.get(), nullptr); + EXPECT_EQ(ptr2.get(), nullptr); +} + +TEST(object_ptr_test, check_destry) +{ + UType::object_ptr ptr(new int(123)), ptr2(ptr); + + ptr.destroy(); + EXPECT_EQ(ptr.get(), nullptr); + EXPECT_EQ(ptr2.get(), nullptr); +} + +TEST(object_ptr_test, check_destroy) +{ + int* test = new int(0); + { + UType::object_ptr ptr(new TestClass(test)); + EXPECT_EQ(*test, 1); + } + EXPECT_EQ(*test, 2); + + *test = 0; + { + UType::object_ptr ptr(new TestClass(test)); + UType::object_ptr ptr2(ptr); + EXPECT_EQ(*test, 1); + } + EXPECT_EQ(*test, 2); +} \ No newline at end of file diff --git a/Tests/SaveMapTest.cpp b/Tests/SaveMapTest.cpp new file mode 100644 index 0000000..a69874b --- /dev/null +++ b/Tests/SaveMapTest.cpp @@ -0,0 +1,185 @@ +#include +#include + +#include "Game/ObjectFactory.hpp" +#include "Game/SaveMap/SaveMap.hpp" + +class CustomObject : public ISave +{ +public: + int num; + std::string str; + double dbl; + + std::shared_ptr save() override + { + return std::make_shared("CustomObject")->SaveInteger("num", num)->SaveString("str", str)->SaveDouble("dbl", dbl); + } + void load(std::shared_ptr save) override + { + num = static_cast(save->GetInteger("num")); + str = save->GetString("str"); + dbl = save->GetDouble("dbl"); + } + + bool operator==(const CustomObject& obj) const + { + return num == obj.num && str == obj.str && dbl == obj.dbl; + } +}; + +FACTORIES_LIST { + GENERATE_FACTORY_OBJECT(CustomObject) +}; +// A compatibility plug +std::vector base_object_factories = {}; + +TEST(SaveMapTest, check_clean) +{ + std::string start_json = +"{\n" +"\t\"id\": 1,\n" +"\t\"name\": \"Ivan Ivanov\",\n" +"\t\"age\": 28,\n" +"\t\"email\": \"ivan@example.com\",\n" +"\t\"roles\": [\"user\", \"editor\", \"moderator\"]\n" +"}"; + std::string end_json = "{\"id\":1,\"name\":\"Ivan Ivanov\",\"age\":28,\"email\":\"ivan@example.com\",\"roles\":[\"user\",\"editor\",\"moderator\"]}"; + + EXPECT_EQ(SaveMap::CleaningJSON(start_json), end_json); +} + +TEST(SaveMapTest, check_load_base_type) +{ + std::string json = +"{\n" + "\t\"Class name\": \"test class\",\n" + "\t\"iTestInt\": 123,\n" + "\t\"dTestDouble\": 123.56,\n" + "\t\"sTestString\": \"string str\",\n" + "\t\"viTestVectorInt\": [\n" + "\t\t1,\n" + "\t\t2,\n" + "\t\t3\n" + "\t],\n" + "\t\"vdTestVectorDouble\": [\n" + "\t\t1.2,\n" + "\t\t3.4,\n" + "\t\t5.6\n" + "\t],\n" + "\t\t\"vsTestVectorString\": [\n" + "\t\t\"str 1\",\n" + "\t\t\"2 str\",\n" + "\t\t\"str 3 str\"\n" + "\t]\n" +"}"; + + std::vector test_vector_int = { 1, 2, 3 }; + std::vector test_vector_double = { 1.2, 3.4, 5.6 }; + std::vector test_vector_string = { "str 1", "2 str", "str 3 str" }; + SaveMap save_map(json); + + EXPECT_EQ(save_map.GetInteger("TestInt"), 123); + EXPECT_EQ(save_map.GetDouble("TestDouble"), 123.56); + EXPECT_EQ(save_map.GetString("TestString"), "string str"); + + EXPECT_EQ(save_map.GetVectorInteger("TestVectorInt").size(), 3); + EXPECT_EQ(save_map.GetVectorDouble("TestVectorDouble").size(), 3); + EXPECT_EQ(save_map.GetVectorString("TestVectorString").size(), 3); + for (auto i = 0; i < 3; i++) + { + EXPECT_EQ(test_vector_int[i], save_map.GetVectorInteger("TestVectorInt")[i]); + EXPECT_EQ(test_vector_double[i], save_map.GetVectorDouble("TestVectorDouble")[i]); + EXPECT_EQ(test_vector_string[i], save_map.GetVectorString("TestVectorString")[i]); + } +} + +TEST(SaveMapTest, check_load_with_custom_type) +{ + std::string json = + "{\n" + "\t\"Class name\": \"test class\",\n" + "\t\"iTestInt\": 123,\n" + "\t\"dTestDouble\": 123.56,\n" + "\t\"sTestString\": \"string str\",\n" + "\t\"viTestVectorInt\": [\n" + "\t\t1,\n" + "\t\t2,\n" + "\t\t3\n" + "\t],\n" + "\t\"vdTestVectorDouble\": [\n" + "\t\t1.2,\n" + "\t\t3.4,\n" + "\t\t5.6\n" + "\t],\n" + "\t\t\"vsTestVectorString\": [\n" + "\t\t\"str 1\",\n" + "\t\t\"2 str\",\n" + "\t\t\"str 3 str\"\n" + "\t],\n" + "\t\"oCustomObject\": {\n" + "\t\t\"Class name\": \"CustomObject\",\n" + "\t\t\"inum\": 123,\n" + "\"sstr\": \"str123\",\n" + "\t\t\"ddbl\": 123.45\n" + "\t},\n" + "\"voCustomObjects\": [" + "{" + "\"Class name\": \"CustomObject\"," + "\"inum\": 123," + "\"sstr\": \"str123\"," + "\"ddbl\": 123.45" + "}," + "{" + "\"Class name\": \"CustomObject\"," + "\"inum\": 321," + "\"sstr\": \"str321\"," + "\"ddbl\": 543.21" + "}" + "]" +"}"; + + std::vector test_vector_int = { 1, 2, 3 }; + std::vector test_vector_double = { 1.2, 3.4, 5.6 }; + std::vector test_vector_string = { "str 1", "2 str", "str 3 str" }; + SaveMap save_map(json); + + EXPECT_EQ(save_map.GetInteger("TestInt"), 123); + EXPECT_EQ(save_map.GetDouble("TestDouble"), 123.56); + EXPECT_EQ(save_map.GetString("TestString"), "string str"); + + EXPECT_EQ(save_map.GetVectorInteger("TestVectorInt").size(), 3); + EXPECT_EQ(save_map.GetVectorDouble("TestVectorDouble").size(), 3); + EXPECT_EQ(save_map.GetVectorString("TestVectorString").size(), 3); + for (auto i = 0; i < 3; i++) + { + EXPECT_EQ(test_vector_int[i], save_map.GetVectorInteger("TestVectorInt")[i]); + EXPECT_EQ(test_vector_double[i], save_map.GetVectorDouble("TestVectorDouble")[i]); + EXPECT_EQ(test_vector_string[i], save_map.GetVectorString("TestVectorString")[i]); + } + + UType::object_ptr obj = static_cast>(save_map.GetObject("CustomObject")); + CustomObject test_obj; + test_obj.num = 123; + test_obj.str = "str123"; + test_obj.dbl = 123.45; + EXPECT_EQ(*obj.get(), test_obj); + + std::vector> vec_obj = reinterpret_cast>&>(save_map.GetVectorObject("CustomObjects")); + std::vector vec_obj_test = { + new CustomObject, + new CustomObject, + }; + vec_obj_test[0]->num = 123; + vec_obj_test[0]->str = "str123"; + vec_obj_test[0]->dbl = 123.45; + vec_obj_test[1]->num = 321; + vec_obj_test[1]->str = "str321"; + vec_obj_test[1]->dbl = 543.21; + for (auto i = 0; i < 2; i++) + { + EXPECT_EQ(*vec_obj[i].get(), *vec_obj_test[i]); + vec_obj[i].destroy(); + delete vec_obj_test[i]; + } +} \ No newline at end of file