Merge pull request #2 from Jiga228/main

Link
This commit is contained in:
Danil
2025-10-19 17:56:37 +07:00
committed by GitHub
55 changed files with 1245 additions and 575 deletions
+1 -1
View File
@@ -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)
-6
View File
@@ -1,6 +0,0 @@
#pragma once
struct CoreCallBacks
{
void (*Quit)();
};
+37 -86
View File
@@ -1,6 +1,6 @@
#include "CoreInstance.h"
#include "CoreInstance.hpp"
#include "SystemCalls.h"
#include "SystemCalls.hpp"
#include <exception>
#include <cstring>
@@ -8,12 +8,9 @@
#include <iostream>
#include <thread>
#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<SaveMap> 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<int>(payload.size()));
main_config_file.close();
SaveMap load_main_config(payload);
main_config_.load(std::make_shared<SaveMap>(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;
}
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);
if (game_ == nullptr)
throw std::runtime_error("Fail create game instance!");
} 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");
}
@@ -6,13 +6,15 @@
#include <vector>
#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,12 +46,7 @@ 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();
@@ -57,27 +54,11 @@ public:
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_; }
};
+107
View File
@@ -0,0 +1,107 @@
#include "ModelManager.hpp"
#include "Log/Log.hpp"
ModelManager::StaticModel::StaticModel(const std::vector<Voxel>& 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<int>(voxels_.size());
sum_moments.y /= static_cast<int>(voxels_.size());
sum_moments.z /= static_cast<int>(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<unsigned int>(*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<Voxel> 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;
}
}
+58
View File
@@ -0,0 +1,58 @@
#pragma once
#include <unordered_map>
#include <vector>
#include <string>
#include <Delegate/Delegate.h>
#include <glm/glm.hpp>
class ModelManager
{
public:
struct Voxel
{
glm::ivec3 loc, color;
int mass;
};
class StaticModel
{
std::string name_;
std::vector<Voxel> voxels_;
glm::vec3 mass_center_;
public:
Delegate<const std::string&> OnDestroy;
StaticModel(const std::vector<Voxel>& voxels, std::string name);
~StaticModel();
const std::vector<Voxel>& 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<unsigned int, owner_counter> models;
static unsigned int FNV1aHash (const char *buf);
void OnDestroySometimeModelCaller(const std::string& name);
public:
Delegate<std::string> OnDestroySometimeModel;
Delegate<StaticModel*> OnLoadSometimeModel;
~ModelManager();
StaticModel* LoadModel(const std::string& name);
void FreeModel(const std::string& name);
};
@@ -1,12 +1,16 @@
#include "RenderEngine.h"
#include "RenderEngine.hpp"
#include <queue>
#include <set>
#include <stdexcept>
#include <fstream>
#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<VkVertexInputAttributeDescription, 2> RenderEngine::Vertex::get_vertex_attribute_descriptions()
{
std::array<VkVertexInputAttributeDescription, 2> 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<VkPresentMo
VkExtent2D RenderEngine::choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window)
{
// Здесь вычисляется допустимое разрешение рендера
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::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<uint32_t>(vertices.size()), 1, 0, 0);
vkCmdDraw(command_buffer, static_cast<uint32_t>(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<UType::object_ptr<Mesh>> meshes = world->GetActorsByClass<Mesh>();
for (auto& i : meshes)
i->load_model(i->GetModelName());
while (!glfwWindowShouldClose(window_))
{
glfwPollEvents();
@@ -8,9 +8,10 @@
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <vulkan/vulkan.h>
#include <glm/glm.hpp>
#include "ModelManager.hpp"
#ifdef _DEBUG
#include <assert.h>
#define VK_CHECK(res) assert(res == VK_SUCCESS)
@@ -35,7 +36,6 @@ class RenderEngine
std::vector<VkPresentModeKHR> present_modes;
};
#pragma region Experemental
struct Vertex
{
glm::vec2 pos;
@@ -43,24 +43,22 @@ class RenderEngine
static VkVertexInputBindingDescription get_binding_description();
static std::array<VkVertexInputAttributeDescription, 2> get_vertex_attribute_descriptions();
};
std::vector<Vertex> vertices = {
std::vector<Vertex> 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<const char*> 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<VkFramebuffer> framebuffers_;
VkCommandPool command_pool_ = VK_NULL_HANDLE;
std::vector<VkCommandBuffer> command_buffers_;
VkBuffer vertex_buffer_ = VK_NULL_HANDLE;
VkDeviceMemory vertex_buffer_memory_ = VK_NULL_HANDLE;
// Sync objects
std::vector<VkSemaphore> image_available_semaphores_, render_finished_semaphores_;
std::vector<VkFence> in_flight_fences_;
@@ -100,6 +101,7 @@ class RenderEngine
void create_buffer(VkDeviceSize size, VkBufferUsageFlags usage,
VkBuffer* buffer, const std::vector<uint32_t>& 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_; }
};
-37
View File
@@ -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);
}
+14
View File
@@ -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();
}
+1 -35
View File
@@ -1,6 +1,6 @@
#ifdef _WIN32
#include "../SystemCalls.h"
#include "../SystemCalls.hpp"
#include <windows.h>
@@ -41,38 +41,4 @@ double System::getMemorySize() {
return static_cast<double>(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<void(*)(CoreCallBacks*)>(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<void(*)()>(GetProcAddress(static_cast<HMODULE>(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<void(*)()>(GetProcAddress(static_cast<HMODULE>(handler), "QuitModule"));
if(quit == nullptr) {
throw std::runtime_error(std::to_string(GetLastError()).c_str());
}
quit();
FreeLibrary(static_cast<HMODULE>(handler));
}
#endif
+3 -1
View File
@@ -1,10 +1,12 @@
#include <iostream>
#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();
+20 -17
View File
@@ -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<SaveMap> Actor::save() noexcept
std::shared_ptr<SaveMap> Actor::save()
{
std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("Actor");
save->SaveObject("loc", &loc)
->SaveObject("rot", &rot)
->SaveObject("scale", &scale)
return std::make_shared<SaveMap>("Actor")
->SaveObject("loc", static_cast<UType::object_ptr<ISave>>(loc_))
->SaveObject("rot", static_cast<UType::object_ptr<ISave>>(rot_))
->SaveObject("scale", UType::object_ptr<ISave>(scale_))
->SaveListStrings("tags", std::move(tags));
return save;
}
void Actor::load(std::shared_ptr<SaveMap> save) noexcept
void Actor::load(std::shared_ptr<SaveMap> save)
{
loc = *reinterpret_cast<Vector3D*>(save->GetObject("loc"));
rot = *reinterpret_cast<Vector3D*>(save->GetObject("rot"));
scale = *reinterpret_cast<Vector3D*>(save->GetObject("scale"));
loc_ = static_cast<UType::object_ptr<Vector3D>>(save->GetObject("loc"));
rot_ = static_cast<UType::object_ptr<Vector3D>>(save->GetObject("rot"));
scale_ = static_cast<UType::object_ptr<Vector3D>>(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);
}
@@ -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<Vector3D> loc_, rot_, scale_;
std::list<std::string> tags;
protected:
virtual void OnDestroy();
public:
Actor();
@@ -24,8 +30,8 @@ public:
Delegate<const Vector3D&> OnSetActorRotate;
#pragma region ISave
virtual std::shared_ptr<SaveMap> save() noexcept override;
virtual void load(std::shared_ptr<SaveMap> save) noexcept override;
std::shared_ptr<SaveMap> save() override;
void load(std::shared_ptr<SaveMap> 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<Vector3D> GetActorLocate() const { return loc_; }
/*
* Изменяет ориентацию в пространстве
* Вызывает делегат OnSetActorRotate
*/
void SetActorRotate(const Vector3D& rot) noexcept;
inline const Vector3D& GetActorRotate() const { return rot; }
inline const UType::object_ptr<Vector3D> GetActorRotate() const { return rot_; }
void AddTag(const std::string& tag) noexcept;
void RemoveTag(const std::string& tag) noexcept;
const std::list<std::string>& GetTags() const { return tags; }
World* GetWorld() const { return world_; }
const std::string& GetName() const { return name_; }
friend class World;
};
+21
View File
@@ -0,0 +1,21 @@
#include "Mesh.hpp"
#include "Game/SaveMap/SaveMap.hpp"
Mesh::Mesh()
{
SetType(Classes::Mesh);
}
std::shared_ptr<SaveMap> Mesh::save()
{
return std::make_shared<SaveMap>("Mesh")
->SaveString("model_name_", model_name_)
->connect_to(Actor::save());
}
void Mesh::load(std::shared_ptr<SaveMap> save)
{
Actor::load(save->getParent());
model_name_ = save->GetString("model_name_");
}
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#include <string>
#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<SaveMap> save() override;
virtual void load(std::shared_ptr<SaveMap> save) override;
#pragma endregion
virtual void load_model(const std::string& model_name) = 0;
const std::string& GetModelName() const { return model_name_; }
};
+36
View File
@@ -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<SaveMap> StaticMesh::save()
{
return std::make_shared<SaveMap>("StaticMesh")->connect_to(Mesh::save());
}
void StaticMesh::load(std::shared_ptr<SaveMap> 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_);
}
+22
View File
@@ -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<SaveMap> save() override;
virtual void load(std::shared_ptr<SaveMap> save) override;
#pragma endregion
void load_model(const std::string& model_name) override;
void OnDestroy() override;
};
+5 -3
View File
@@ -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<ObjectFactory> base_object_factories = {
GENERATE_FACTORY_OBJECT(Actor)
GENERATE_FACTORY_OBJECT(StaticMesh)
GENERATE_FACTORY_OBJECT(Vector2D)
GENERATE_FACTORY_OBJECT(Vector3D)
};
+5 -13
View File
@@ -1,14 +1,14 @@
#include "GameInstance.h"
#include "GameInstance.hpp"
#include <filesystem>
#include <fstream>
#include <chrono>
#include <thread>
#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<WorldFactory> 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<SaveMap>(data));
}
GameInstance::~GameInstance()
@@ -17,8 +17,10 @@ class GameInstance
std::atomic<bool> 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;
};
+1 -1
View File
@@ -1,4 +1,4 @@
#include "Resource.h"
#include "Resource.hpp"
#include <stdexcept>
#include <cstring>
@@ -1,6 +1,6 @@
#pragma once
#include "IResource.h"
#include "IResource.hpp"
#include <mutex>
#include <fstream>
#include <string>
+74 -52
View File
@@ -1,8 +1,8 @@
#include "SaveMap.h"
#include "SaveMap.hpp"
#include <filesystem>
#include <stdexcept>
#include "Game/ObjectFactory.h"
#include "Game/ObjectFactory.hpp"
extern std::vector<ObjectFactory> factories;
extern std::vector<ObjectFactory> 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<ISave> object_ptr(MakeObjectByName(object_name));
object_ptr->load(std::make_shared<SaveMap>(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<long long>();
@@ -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<ISave*>();
save_vector_objects[key] = std::vector<UType::object_ptr<ISave>>();
if (arr_data.length() == 2)
continue;
std::vector<ISave*>& vector_object = save_vector_objects[key];
std::vector<UType::object_ptr<ISave>>& 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<ISave> object_ptr(MakeObjectByName(object_name));
object_ptr->load(std::make_shared<SaveMap>(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<long long>();
@@ -267,10 +272,10 @@ SaveMap::SaveMap(const std::string& json_data)
}
} else if (name[1] == 'o')
{
save_list_objects[key] = std::list<ISave*>();
save_list_objects[key] = std::list<UType::object_ptr<ISave>>();
if (arr_data.length() == 2)
continue;
std::list<ISave*>& list_object = save_list_objects[key];
std::list<UType::object_ptr<ISave>>& 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<ISave> object_ptr(MakeObjectByName(object_name));
object_ptr->load(std::make_shared<SaveMap>(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<SaveMap>(str);
}
}
@@ -384,7 +389,7 @@ std::shared_ptr<SaveMap> SaveMap::SaveString(const char* name, const std::string
return std::shared_ptr<SaveMap>(this);
}
std::shared_ptr<SaveMap> SaveMap::SaveObject(const char* name, ISave* object) noexcept
std::shared_ptr<SaveMap> SaveMap::SaveObject(const char* name, UType::object_ptr<ISave> object) noexcept
{
save_objects[name] = object;
return std::shared_ptr<SaveMap>(this);
@@ -408,7 +413,7 @@ std::shared_ptr<SaveMap> SaveMap::SaveVectorStrings(const char* name, std::vecto
return std::shared_ptr<SaveMap>(this);
}
std::shared_ptr<SaveMap> SaveMap::SaveVectorObject(const char* name, std::vector<ISave*>&& value) noexcept
std::shared_ptr<SaveMap> SaveMap::SaveVectorObject(const char* name, std::vector<UType::object_ptr<ISave>>&& value) noexcept
{
save_vector_objects[name] = std::move(value);
return std::shared_ptr<SaveMap>(this);
@@ -432,7 +437,7 @@ std::shared_ptr<SaveMap> SaveMap::SaveListStrings(const char* name, std::list<st
return std::shared_ptr<SaveMap>(this);
}
std::shared_ptr<SaveMap> SaveMap::SaveListObject(const char* name, std::list<ISave*>&& value) noexcept
std::shared_ptr<SaveMap> SaveMap::SaveListObject(const char* name, std::list<UType::object_ptr<ISave>>&& value) noexcept
{
save_list_objects[name] = std::move(value);
return std::shared_ptr<SaveMap>(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<ISave> SaveMap::GetObject(const char* name)
{
return save_objects[name];
}
@@ -473,7 +478,7 @@ std::vector<std::string> SaveMap::GetVectorString(const char* name)
return save_vector_strings[name];
}
std::vector<ISave*>& SaveMap::GetVectorObject(const char* name)
std::vector<UType::object_ptr<ISave>>& SaveMap::GetVectorObject(const char* name)
{
return save_vector_objects[name];
}
@@ -493,7 +498,7 @@ std::list<std::string>& SaveMap::GetListString(const char* name)
return save_list_strings[name];
}
std::list<ISave*>& SaveMap::GetListObject(const char* name)
std::list<UType::object_ptr<ISave>>& 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<SaveMap>& parent)
std::shared_ptr<SaveMap> SaveMap::connect_to(const std::shared_ptr<SaveMap>& parent)
{
if (this->parent_ != nullptr)
throw std::runtime_error("Can't connect to second parent");
this->parent_ = parent;
return this;
return std::shared_ptr<SaveMap>(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;
}
@@ -1,8 +1,9 @@
#pragma once
#include "ISave.h"
#include "Types/object_ptr.hpp"
#include <map>
#include <unordered_map>
#include <memory>
#include <string>
#include <vector>
@@ -14,22 +15,22 @@ class SaveMap final
std::shared_ptr<SaveMap> parent_;
// Индивидуальные значения
std::map<std::string, long long> save_long;
std::map<std::string, double> save_double;
std::map<std::string, std::string> save_string;
std::map<std::string, ISave*> save_objects;
std::unordered_map<std::string, long long> save_long;
std::unordered_map<std::string, double> save_double;
std::unordered_map<std::string, std::string> save_string;
std::unordered_map<std::string, UType::object_ptr<ISave>> save_objects;
// Массивы
std::map<std::string, std::vector<long long>> save_vector_integer;
std::map<std::string, std::vector<double>> save_vector_double;
std::map<std::string, std::vector<ISave*>> save_vector_objects;
std::map<std::string, std::vector<std::string>> save_vector_strings;
std::unordered_map<std::string, std::vector<long long>> save_vector_integer;
std::unordered_map<std::string, std::vector<double>> save_vector_double;
std::unordered_map<std::string, std::vector<UType::object_ptr<ISave>>> save_vector_objects;
std::unordered_map<std::string, std::vector<std::string>> save_vector_strings;
// Связаные списки
std::map<std::string, std::list<long long>> save_list_integer;
std::map<std::string, std::list<double>> save_list_double;
std::map<std::string, std::list<ISave*>> save_list_objects;
std::map<std::string, std::list<std::string>> save_list_strings;
std::unordered_map<std::string, std::list<long long>> save_list_integer;
std::unordered_map<std::string, std::list<double>> save_list_double;
std::unordered_map<std::string, std::list<UType::object_ptr<ISave>>> save_list_objects;
std::unordered_map<std::string, std::list<std::string>> save_list_strings;
static ISave* MakeObjectByName(const std::string& name);
@@ -47,29 +48,29 @@ public:
std::shared_ptr<SaveMap> SaveInteger(const char* name, int value) noexcept;
std::shared_ptr<SaveMap> SaveDouble(const char* name, double value) noexcept;
std::shared_ptr<SaveMap> SaveString(const char* name, const std::string& value) noexcept;
std::shared_ptr<SaveMap> SaveObject(const char* name, ISave* object) noexcept;
std::shared_ptr<SaveMap> SaveObject(const char* name, UType::object_ptr<ISave> object) noexcept;
std::shared_ptr<SaveMap> SaveVectorInteger(const char* name, std::vector<long long>&& value) noexcept;
std::shared_ptr<SaveMap> SaveVectorDouble(const char* name, std::vector<double>&& value) noexcept;
std::shared_ptr<SaveMap> SaveVectorStrings(const char* name, std::vector<std::string>&& value) noexcept;
std::shared_ptr<SaveMap> SaveVectorObject(const char* name, std::vector<ISave*>&& value) noexcept;
std::shared_ptr<SaveMap> SaveVectorObject(const char* name, std::vector<UType::object_ptr<ISave>>&& value) noexcept;
std::shared_ptr<SaveMap> SaveListInteger(const char* name, std::list<long long>&& value) noexcept;
std::shared_ptr<SaveMap> SaveListDouble(const char* name, std::list<double>&& value) noexcept;
std::shared_ptr<SaveMap> SaveListStrings(const char* name, std::list<std::string>&& value) noexcept;
std::shared_ptr<SaveMap> SaveListObject(const char* name, std::list<ISave*>&& value) noexcept;
std::shared_ptr<SaveMap> SaveListObject(const char* name, std::list<UType::object_ptr<ISave>>&& 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<ISave> GetObject(const char* name);
std::vector<long long>& GetVectorInteger(const char* name);
std::vector<double>& GetVectorDouble(const char* name);
std::vector<std::string> GetVectorString(const char* name);
std::vector<ISave*>& GetVectorObject(const char* name);
std::vector<UType::object_ptr<ISave>>& GetVectorObject(const char* name);
std::list<long long>& GetListInteger(const char* name);
std::list<double>& GetListDouble(const char* name);
std::list<std::string>& GetListString(const char* name);
std::list<ISave*>& GetListObject(const char* name);
std::list<UType::object_ptr<ISave>>& GetListObject(const char* name);
std::shared_ptr<SaveMap> 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<SaveMap>& parent);
std::shared_ptr<SaveMap> connect_to(const std::shared_ptr<SaveMap>& parent);
static std::string CleaningJSON(const std::string& json_data);
};
+31 -11
View File
@@ -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<SaveMap> World::save()
{
std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("World");
save->SaveListObject("Actors", std::move(reinterpret_cast<std::list<ISave*>&>(actors)));
return save;
}
void World::load(std::shared_ptr<SaveMap> save)
{
actors = std::move(reinterpret_cast<std::list<Actor*>&>(save->GetListObject("Actors")));
std::vector<std::string> actors_IDs = save->GetVectorString("ActorsIDs");
std::list<UType::object_ptr<Actor>> act = std::move(reinterpret_cast<std::list<UType::object_ptr<Actor>>&>(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<Actor> ptr)
{
if (ptr.get() == nullptr)
return;
std::string name = ptr->GetName();
actors_map.erase(name);
ptr->OnDestroy();
ptr.destroy();
}
-73
View File
@@ -1,73 +0,0 @@
#pragma once
#include <list>
#include <vector>
#include <string>
#include "RTTI.h"
#include "Game/Actors/Actor.h"
class GameInstance;
class World : public ISave
{
GameInstance& game_instance;
// Actors only
std::list<Actor*> 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<SaveMap> save() override;
void load(std::shared_ptr<SaveMap> save) override;
#pragma endregion
template<class T, class Container = std::vector<T*>>
Container GetActorsByClass()
{
Container list;
for (auto i = actors.cbegin(); i != actors.cend(); ++i)
{
if (RTTI::IsA<T>(*i))
list.push_back(*i);
}
return list;
}
template<class T>
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<class Container = std::vector<Actor*>>
Container GetActorsByTag(std::string tag)
{
Container container;
for (auto& i : actors)
{
const std::list<std::string>& tags = i->GetTags();
for (auto& j : tags)
{
if (j == tag)
container.push_back(i);
}
}
return container;
}
};
+85
View File
@@ -0,0 +1,85 @@
#pragma once
#include <list>
#include <unordered_map>
#include <vector>
#include <string>
#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<std::string, UType::object_ptr<Actor>> 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<SaveMap> save() override;
void load(std::shared_ptr<SaveMap> save) override;
#pragma endregion
template<class T>
std::vector<UType::object_ptr<T>> GetActorsByClass()
{
std::vector<UType::object_ptr<T>> list;
for (auto i = actors_map.cbegin(); i != actors_map.cend(); ++i)
{
if (T* cast_object = RTTI::dyn_cast<T, Actor>(i->second.get()))
list.push_back(UType::object_ptr<T>(cast_object));
}
return list;
}
template<class T>
UType::object_ptr<T> SpawnActorFormClass(std::string name, const Vector3D& loc = { 0, 0, 0 }, const Vector3D& rot = { 0, 0, 0 })
{
UType::object_ptr<T> object(new T());
object->SetActorLocate(loc);
object->SetActorRotate(rot);
static_cast<Actor*>(object)->world_ = this;
actors_map.try_emplace(name, object);
return object;
}
void DestroyActor(UType::object_ptr<Actor> ptr);
template<class T, class Container = std::vector<T*>>
Container GetActorsByTag(std::string tag)
{
Container container;
for (auto& i : actors_map)
{
const std::list<std::string>& tags = i.second->GetTags();
for (auto& j : tags)
{
if (j == tag)
container.push_back(i);
}
}
return container;
}
template<class T>
UType::object_ptr<T> GetActorByID(const std::string& id)
{
return actors_map[id];
}
};
@@ -1,6 +1,9 @@
#pragma once
#include <vector>
#include <fstream>
#include <string>
#include "Game/SaveMap/SaveMap.hpp"
class GameInstance;
class World;
@@ -16,7 +19,21 @@ struct WorldFactory
#define WORLDS_LIST std::vector<WorldFactory> 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<SaveMap>(data));\
return world;\
}},
/*
* Пример использования:
+8 -8
View File
@@ -1,39 +1,39 @@
#include "Log.h"
#include "Log.hpp"
#include <iostream>
#include <mutex>
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';
-9
View File
@@ -1,9 +0,0 @@
#pragma once
#include <string>
void Log(const char* msg);
void Log(const std::string& msg);
void Message(const char* msg);
void Message(const std::string& msg);
+12
View File
@@ -0,0 +1,12 @@
#pragma once
#include <string>
namespace Loging
{
void Log(const char* msg);
void Log(const std::string& msg);
void Message(const char* msg);
void Message(const std::string& msg);
}
+2 -2
View File
@@ -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)
{}
+3
View File
@@ -0,0 +1,3 @@
#include "object_ptr.hpp"
std::unordered_map<void*, UType::counter::counter_owners> UType::counter::owners_map;
+175
View File
@@ -0,0 +1,175 @@
#pragma once
#include <mutex>
#include <unordered_map>
#include <list>
namespace UType
{
template<typename Ty>
class object_ptr;
class counter
{
struct counter_owners
{
std::atomic_bool is_destroyed;
std::mutex mutex;
std::list<void*> 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<void*, counter_owners> owners_map;
public:
template<typename Ty>
static void add_owner(object_ptr<Ty>& 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<std::mutex> lock(counter->second.mutex);
counter->second.owners.push_back(&ptr);
}
else
ptr.ptr_.store(nullptr);
}
template<typename Ty>
static void remove_owner(object_ptr<Ty>& 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<object_ptr<Ty>*>(owner)->ptr_.store(nullptr);
delete static_cast<Ty*>(counter->first);
owners_map.erase(counter);
}
}
}
template<typename Ty>
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<object_ptr<Ty>*>(owner)->ptr_.store(nullptr);
delete ptr;
owners_map.erase(counter);
}
}
};
template<typename Ty>
class object_ptr
{
std::atomic<Ty*> ptr_;
public:
explicit object_ptr(Ty* ptr = nullptr)
{
ptr_.store(ptr);
if (ptr) counter::add_owner<Ty>(*this);
}
object_ptr(const object_ptr& ptr)
{
ptr_.store(ptr.ptr_);
if (ptr.ptr_) counter::add_owner<Ty>(*this);
}
object_ptr(object_ptr&& ptr) noexcept
{
ptr_.store(ptr.ptr_);
if (ptr.ptr_) counter::add_owner<Ty>(*this);
ptr.ptr_.store(nullptr);
}
~object_ptr()
{
if (ptr_) counter::remove_owner<Ty>(*this);
}
void reset(Ty* new_ptr = nullptr)
{
if (ptr_) counter::remove_owner<Ty>(*this);
ptr_.store(new_ptr);
if (new_ptr) counter::add_owner<Ty>(*this);
}
void reset(const object_ptr& ptr)
{
if (ptr_) counter::remove_owner<Ty>(*this);
ptr_.store(ptr.ptr_);
if (ptr.ptr_) counter::add_owner<Ty>(*this);
}
void destroy()
{
if (ptr_) counter::remove_object<Ty>(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<Ty>& operator=(const object_ptr<Ty>& ptr)
{
reset(ptr);
return *this;
}
template<typename target_Ty>
explicit operator object_ptr<target_Ty>() const noexcept
{
return object_ptr<target_Ty>(reinterpret_cast<target_Ty*>(ptr_.load()));
}
friend class counter;
};
}
+1 -1
View File
@@ -13,5 +13,5 @@ template<class T> struct Meta;
// Enum type classes
enum class Classes
{
IRTTI, IResource, Actor, TestActor
IRTTI, IResource, Actor, TestActor, Mesh, StaticMesh, World, TestWorld
};
-14
View File
@@ -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()
-57
View File
@@ -1,57 +0,0 @@
#include "ModuleInstance.h"
#include <mutex>
#include <thread>
#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<std::mutex> lock(mModuleInstance);
callbacks_ = callbacks;
if(module == nullptr)
module = Factory();
}
void StartModule()
{
std::lock_guard<std::mutex> lock(mModuleInstance);
if (module != nullptr)
moduleThread = new std::thread(&ModuleInstance::start, module);
}
void QuitModule()
{
std::lock_guard<std::mutex> lock(mModuleInstance);
if(module != nullptr)
{
module->stop();
moduleThread->join();
delete module;
module = nullptr;
delete moduleThread;
moduleThread = nullptr;
}
}
-47
View File
@@ -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<void*>(&InitModule);} \
EXPORT void* protect_start() {return reinterpret_cast<void*>(&StartModule);} \
EXPORT void* protect_quit() {return reinterpret_cast<void*>(&QuitModule);} \
}\
ModuleInstance* Factory() { return static_cast<ModuleInstance*>(new Class()); }
struct CoreCallBacks;
class ModuleInstance {
public:
Delegate<void> 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();
}
+68 -1
View File
@@ -1 +1,68 @@
{"Class name":"TestWorld","dtime":5.000000,"Parent parameters":{"Class name":"World","loActors":[]}}
{
"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":[]
}
}
}
]
}
}
+7 -1
View File
@@ -1 +1,7 @@
{"Class name":"MainConfig","dmin_memory_size":"4096.0","imin_CPU_count":"1","sgame_name":"Test Game","sbase_world":"TestWorld","vsmodules_names":[]}
{
"Class name": "MainConfig",
"dmin_memory_size": 4096.0,
"imin_CPU_count": 1,
"sgame_name": "Test Game",
"sbase_world": "TestWorld"
}
+2 -2
View File
@@ -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");
}
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "Game/Actors/Actor.h"
#include "Game/Actors/Actor.hpp"
GENERATE_META(TestActor)
class TestActor final : public Actor
+1 -1
View File
@@ -1,4 +1,4 @@
#include "Game/ObjectFactory.h"
#include "Game/ObjectFactory.hpp"
#include "../Actors/TestActor.h"
+1 -1
View File
@@ -1,4 +1,4 @@
#include "Game/WorldFactory.h"
#include "Game/WorldFactory.hpp"
#include "../Worlds/TestWorld.h"
+3 -3
View File
@@ -1,10 +1,10 @@
#include "TestGameInstance.h"
#include "Game/Resource/Resource.h"
#include "Game/Resource/Resource.hpp"
#include <iostream>
#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)
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "Game/GameInstance.h"
#include "Game/GameInstance.hpp"
class TestGameInstance : public GameInstance
{
+15 -5
View File
@@ -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<UType::object_ptr<Actor>> meshes = GetActorsByClass<Actor>();
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<UType::object_ptr<Mesh>> meshes = GetActorsByClass<Mesh>();
if (!meshes.empty())
{
Loging::Message("TestWorld destroy: " + meshes[0]->GetName());
DestroyActor(static_cast<UType::object_ptr<Actor>>(meshes[0]));
time = 7.0;
return;
}
Loging::Message("TestWorld: Time out");
GetGameInstance().quit();
}
}
+2 -1
View File
@@ -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;
+31
View File
@@ -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)
+59
View File
@@ -0,0 +1,59 @@
#include <gtest/gtest.h>
#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<int> ptr(test);
EXPECT_EQ(*ptr.get(), 123);
UType::object_ptr<int> 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<int> 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<TestClass> ptr(new TestClass(test));
EXPECT_EQ(*test, 1);
}
EXPECT_EQ(*test, 2);
*test = 0;
{
UType::object_ptr<TestClass> ptr(new TestClass(test));
UType::object_ptr<TestClass> ptr2(ptr);
EXPECT_EQ(*test, 1);
}
EXPECT_EQ(*test, 2);
}
+185
View File
@@ -0,0 +1,185 @@
#include <gtest/gtest.h>
#include <iostream>
#include "Game/ObjectFactory.hpp"
#include "Game/SaveMap/SaveMap.hpp"
class CustomObject : public ISave
{
public:
int num;
std::string str;
double dbl;
std::shared_ptr<SaveMap> save() override
{
return std::make_shared<SaveMap>("CustomObject")->SaveInteger("num", num)->SaveString("str", str)->SaveDouble("dbl", dbl);
}
void load(std::shared_ptr<SaveMap> save) override
{
num = static_cast<int>(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<ObjectFactory> 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<int> test_vector_int = { 1, 2, 3 };
std::vector<double> test_vector_double = { 1.2, 3.4, 5.6 };
std::vector<std::string> 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<int> test_vector_int = { 1, 2, 3 };
std::vector<double> test_vector_double = { 1.2, 3.4, 5.6 };
std::vector<std::string> 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<CustomObject> obj = static_cast<UType::object_ptr<CustomObject>>(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<UType::object_ptr<CustomObject>> vec_obj = reinterpret_cast<std::vector<UType::object_ptr<CustomObject>>&>(save_map.GetVectorObject("CustomObjects"));
std::vector<CustomObject*> 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];
}
}