Вынес рендер в отдельный модуль. Сделал систему вызовов для модулй к ядру. Исправил баг в SaveMap. Убрал поддержку linux, так как трудно поддерживать обе платформы. Убрал тесты для linux.

This commit is contained in:
Jiga228
2025-09-15 19:13:39 +07:00
parent 9bf9d678f7
commit f15c8b09cd
18 changed files with 193 additions and 227 deletions
+6
View File
@@ -0,0 +1,6 @@
#pragma once
struct CoreCallBacks
{
void (*Quit)();
};
+29 -6
View File
@@ -1,12 +1,17 @@
#include "CoreInstance.h"
#include "SystemCalls.h"
#include "GLFW/glfw3.h"
#include <exception>
#include <cstring>
#include <fstream>
#include <iostream>
#include "Log/Log.h"
CoreInstance* CoreInstance::self = nullptr;
std::shared_ptr<SaveMap> CoreInstance::MainConfig::save()
{
return std::make_shared<SaveMap>("MainConfig");
@@ -17,12 +22,31 @@ void CoreInstance::MainConfig::load(std::shared_ptr<SaveMap> save)
game_name = save->GetString("game_name");
base_world = save->GetString("base_world");
modules_names = save->GetVectorString("modules_names");
min_memory_size = save->GetDouble("min_memory_size");
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();
if (!glfwInit())
{
std::string msg;
const char* error;
glfwGetError(&error);
throw std::runtime_error("Fail initialize GLFW");
}
std::ifstream main_config_file(main_config_name);
if (main_config_file.fail())
@@ -30,15 +54,14 @@ CoreInstance::CoreInstance()
std::string payload;
std::getline(main_config_file, payload);
std::shared_ptr<SaveMap> load_main_config = std::make_shared<SaveMap>(payload);
SaveMap load_main_config(payload);
main_config.load(load_main_config);
main_config.load(std::make_shared<SaveMap>(load_main_config));
}
CoreInstance::~CoreInstance()
{
if (game != nullptr)
delete game;
delete game;
for (auto& module : modules)
System::QuitModule(module.handler);
@@ -53,7 +76,7 @@ void CoreInstance::start()
{
try
{
void* handler = System::InitModule(name.c_str(), *this);
void* handler = System::InitModule(name.c_str(), &callbacks_);
modules.push_back(Module {name.c_str(), handler});
} catch (const std::exception& e)
{
@@ -96,7 +119,7 @@ void* CoreInstance::enableModule(const char* name)
throw std::runtime_error("Module already enabled");
}
void* module = System::InitModule(name, *this);
void* module = System::InitModule(name, &callbacks_);
modules.push_back({ name, module });
return module;
}
+19 -13
View File
@@ -5,8 +5,10 @@
#include "Game/GameInstance.h"
#include "Game/SaveMap/SaveMap.h"
#include "Core/CoreCallBacks.h"
class CoreInstance {
static CoreInstance* self;
struct Module {
const char* name;
void* handler;
@@ -17,37 +19,41 @@ class CoreInstance {
std::string game_name;
std::string base_world;
std::vector<std::string> modules_names;
double min_memory_size = -1;
int min_CPU_count = -1;
std::shared_ptr<SaveMap> save() override;
void load(std::shared_ptr<SaveMap> save) override;
};
#pragma region Key words for main config
const char* key_base_world= "base_world";
const char* key_modules = "modules";
#pragma endregion
#pragma region config parameters
const char* main_config_name = "main_config.conf";
// std::string base_world;
// std::vector<std::string> modules_names;
// std::string game_name;
MainConfig main_config;
#pragma endregion
int countCPU;
unsigned long long memorySize;
// Memory in MB
double memorySize;
std::list<Module> modules;
GameInstance* game = nullptr;
CoreCallBacks callbacks_;
#pragma region Callbacks
static void Quit_callback();
#pragma endregion
public:
CoreInstance();
~CoreInstance();
void start();
/**
* This method quit game
* Async
*/
int getCountCPU() const { return countCPU; }
unsigned long long getMemorySize() const { return memorySize; }
double getMemorySize() const { return memorySize; }
/**
* @throws std::runtime_error if module isn't enabled
+3 -12
View File
@@ -18,12 +18,12 @@ int System::getCountCPU()
return num_cores;
}
unsigned long long System::getMemorySize()
double System::getMemorySize()
{
struct sysinfo info{};
if(sysinfo(&info) == -1)
if(sysinfo(&info) == -1)
std::runtime_error("Fail get system info");
return info.totalram;
return info.totalram / 1024 / 1024;
}
void* System::InitModule(const char* ModuleName, CoreInstance& core)
@@ -52,15 +52,6 @@ void System::StartModule(void* handler)
start();
}
void System::StopModule(void* handler)
{
void(*stop)() = reinterpret_cast<void(*)()>(dlsym(handler, "StopModule"));
if(stop == nullptr)
std::runtime_error("Module mot contins StopModule");
stop();
dlclose(handler);
}
void System::QuitModule(void* handler)
{
void(*quit)() = reinterpret_cast<void(*)()>(dlsym(handler, "QuitModule"));
-153
View File
@@ -1,153 +0,0 @@
#include "RenderEngine.h"
#include <stdexcept>
#include <vector>
#ifdef _DEBUG
#include "Log/Log.h"
#include <assert.h>
#define VK_CHECK(res) assert(res == VK_SUCCESS)
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData) {
std::string msg = "validation layer: ";
msg += pCallbackData->pMessage;
Log(msg);
return VK_FALSE;
}
VkResult RenderEngine::enable_layer_validation(VkInstance instance, VkDebugUtilsMessengerCreateInfoEXT* create_info)
{
PFN_vkCreateDebugUtilsMessengerEXT debug_creator = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"));
return debug_creator(instance, create_info, nullptr, &debug_messenger_);
}
#else
#define VK_CHECK(res) if ((res) != VK_SUCCESS) throw std::runtime_error("Vulkan error: " + std::to_string(res))
#endif
std::vector<const char*> RenderEngine::get_required_extensions()
{
uint32_t extensions_count = 0;
const char** glfw_extension = glfwGetRequiredInstanceExtensions(&extensions_count);
std::vector<const char*> extensions(glfw_extension, glfw_extension + extensions_count);
#ifdef _DEBUG
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
#endif
return extensions;
}
void RenderEngine::render_thread_func()
{
window = glfwCreateWindow(640, 480, "UwU Engine", nullptr, nullptr);
if (!window)
{
glfwTerminate();
throw std::runtime_error("Fail create window");
}
while (!glfwWindowShouldClose(window))
{
glfwSwapBuffers(window);
glfwPollEvents();
}
onCloseWindow.Call();
}
RenderEngine::RenderEngine(const std::string& app_name,
int major_app_version, int minor_app_version, int patch_app_version,
int major_engine_version, int minor_engine_version, int patch_engine_version) :
render_thread(nullptr), window(nullptr)
#ifdef _DEBUG
, debug_messenger_(nullptr)
#endif
{
if (!glfwInit())
throw std::runtime_error("Fail initialize GLFW");
{
std::vector<const char*> extensions = get_required_extensions();
std::vector<const char*> layers = {
#ifdef _DEBUG
"VK_LAYER_KHRONOS_validation"
#endif
};
VkApplicationInfo app_info{};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
app_info.apiVersion = VK_API_VERSION_1_0;
app_info.applicationVersion = VK_MAKE_VERSION(major_app_version, minor_app_version, patch_app_version);
app_info.pApplicationName = app_name.c_str();
app_info.pEngineName = "UwU Engine";
app_info.engineVersion = VK_MAKE_VERSION(major_engine_version, minor_engine_version, patch_engine_version);
VkInstanceCreateInfo instance_create_info{};
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instance_create_info.pApplicationInfo = &app_info;
instance_create_info.enabledExtensionCount = extensions.size();
instance_create_info.ppEnabledExtensionNames = extensions.data();
instance_create_info.enabledLayerCount = layers.size();
instance_create_info.ppEnabledLayerNames = layers.data();
#ifdef _DEBUG
VkDebugUtilsMessengerCreateInfoEXT debug_messenger_create_info{};
debug_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
debug_messenger_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
debug_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
debug_messenger_create_info.pfnUserCallback = &debugCallback;
instance_create_info.pNext = &debug_messenger_create_info;
#endif
VK_CHECK(vkCreateInstance(&instance_create_info, nullptr, &instance_));
#ifdef _DEBUG
VK_CHECK(enable_layer_validation(instance_, &debug_messenger_create_info));
#endif
}
{
uint32_t device_count = 0;
std::vector<VkPhysicalDevice> devices;
VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, nullptr));
VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, devices.data()));
for (const auto& device : devices)
{
VkPhysicalDeviceProperties device_properties;
vkGetPhysicalDeviceProperties(device, &device_properties);
}
}
}
RenderEngine::~RenderEngine()
{
if (window != nullptr && !glfwWindowShouldClose(window))
glfwSetWindowShouldClose(window, true);
if (render_thread != nullptr)
{
render_thread->join();
delete render_thread;
}
#ifdef _DEBUG
if (debug_messenger_ != nullptr && instance_ != nullptr) {
PFN_vkDestroyDebugUtilsMessengerEXT destroyer_messenger = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(vkGetInstanceProcAddr(instance_, "vkDestroyDebugUtilsMessengerEXT"));
destroyer_messenger(instance_, debug_messenger_, nullptr);
}
#endif
if (instance_ != nullptr)
vkDestroyInstance(instance_, nullptr);
if (window != nullptr)
glfwDestroyWindow(window);
glfwTerminate();
}
void RenderEngine::start()
{
render_thread = new std::thread(&RenderEngine::render_thread_func, this);
}
-36
View File
@@ -1,36 +0,0 @@
#pragma once
#define GLFW_INCLUDE_VULKAN
#include "Delegate/Delegate.h"
#include <string>
#include <thread>
#include <vector>
#include "GLFW/glfw3.h"
class RenderEngine
{
std::thread* render_thread;
GLFWwindow* window;
VkInstance instance_;
#ifdef _DEBUG
VkResult enable_layer_validation(VkInstance instance, VkDebugUtilsMessengerCreateInfoEXT* create_info);
VkDebugUtilsMessengerEXT debug_messenger_;
#endif
static std::vector<const char*> get_required_extensions();
void render_thread_func();
public:
Delegate<void> onCloseWindow;
RenderEngine(const std::string& app_name,
int major_app_version, int minor_app_version, int patch_app_version,
int major_engine_version, int minor_engine_version, int patch_engine_version);
~RenderEngine();
void start();
};
+8 -8
View File
@@ -2,32 +2,32 @@
class CoreInstance;
struct CoreCallBacks;
namespace System {
/**
* @throws std::exception if the operation finished with failed
* @return count CPU
*/
int getCountCPU();
unsigned long long getMemorySize();
/*
* @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, CoreInstance& core);
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);
/**
* Stop the module when unload there
* @throws std::runtime_error if module not contains StopModule function
*/
void StopModule(void* handler) noexcept(false);
/**
* Call stop module
+5 -14
View File
@@ -33,15 +33,15 @@ int System::getCountCPU() {
return physicalCoreCount;
}
unsigned long long System::getMemorySize() {
double System::getMemorySize() {
MEMORYSTATUSEX memStatus{};
memStatus.dwLength = sizeof(memStatus);
GlobalMemoryStatusEx(&memStatus);
return memStatus.ullTotalPhys;
return memStatus.ullTotalPhys / 1024 / 1024;
}
void* System::InitModule(const char* ModuleName, CoreInstance& core) {
void* System::InitModule(const char* ModuleName, CoreCallBacks* callbacks) {
std::string fileName = ModuleName;
fileName += ".dll";
@@ -49,11 +49,11 @@ void* System::InitModule(const char* ModuleName, CoreInstance& core) {
if(hModule == nullptr)
throw std::runtime_error(std::to_string(GetLastError()).c_str());
void(*load)(CoreInstance&) = reinterpret_cast<void(*)(CoreInstance&)>(GetProcAddress(hModule, "InitModule"));
void(*load)(CoreCallBacks*) = reinterpret_cast<void(*)(CoreCallBacks*)>(GetProcAddress(hModule, "InitModule"));
if(load == nullptr) {
throw std::runtime_error(std::to_string(GetLastError()).c_str());
}
load(core);
load(callbacks);
return hModule;
}
@@ -66,15 +66,6 @@ void System::StartModule(void* handler) {
start();
}
void System::StopModule(void* handler) {
void(*stop)() = reinterpret_cast<void(*)()>(GetProcAddress(static_cast<HMODULE>(handler), "StopModule"));
if(stop == nullptr) {
throw std::runtime_error(std::to_string(GetLastError()).c_str());
}
stop();
FreeLibrary(static_cast<HMODULE>(handler));
}
void System::QuitModule(void* handler) {
void(*quit)() = reinterpret_cast<void(*)()>(GetProcAddress(static_cast<HMODULE>(handler), "QuitModule"));
if(quit == nullptr) {
-4
View File
@@ -6,7 +6,6 @@
#include <thread>
#include "Core/CoreInstance.h"
#include "Core/RenderEngine.h"
#include "Game/WorldFactory.h"
#include "SaveMap/SaveMap.h"
#include "Game/World/World.h"
@@ -15,8 +14,6 @@ extern std::vector<WorldFactory> world_factories;
GameInstance::GameInstance(CoreInstance& core) : core(core)
{
render_engine_ = std::make_unique<RenderEngine>(core.getGameName(), 0, 0, 0, 0, 0, 0);
render_engine_->onCloseWindow.bind(this, &GameInstance::quit);
const std::string& base_world = core.getBaseWorldName();
// Init directories
@@ -51,7 +48,6 @@ GameInstance::~GameInstance()
void GameInstance::start()
{
render_engine_->start();
world->BeginPlay();
auto first = std::chrono::steady_clock::now();
-2
View File
@@ -5,7 +5,6 @@
class CoreInstance;
class World;
class RenderEngine;
#define GENERATE_FACTORY_GAME_INSTANCE(Class) \
GameInstance* GameFactory(CoreInstance& core) { return new Class(core); }
@@ -14,7 +13,6 @@ class GameInstance
{
CoreInstance& core;
World* world = nullptr;
std::unique_ptr<RenderEngine> render_engine_;
std::atomic<bool> is_running = true;
+4 -4
View File
@@ -49,17 +49,17 @@ SaveMap::SaveMap(const std::string& json_data)
}
if (name[0] == 'i') {
size_t begin = json_data.find(':', i) + 1;
size_t begin = json_data.find(':', i) + 2;
size_t end = i = json_data.find_first_of(",}", i);
i++;
std::string value = json_data.substr(begin, end - begin);
std::string value = json_data.substr(begin, end - begin - 1);
save_long[name.c_str() + 1] = std::stoll(value);
} else if (name[0] == 'd')
{
size_t begin = json_data.find(':', i) + 1;
size_t begin = json_data.find(':', i) + 2;
size_t end = i = json_data.find_first_of(",}", i);
i++;
std::string value = json_data.substr(begin, end - begin);
std::string value = json_data.substr(begin, end - begin - 1);
save_double[name.c_str() + 1] = std::stod(value);
} else if (name[0] == 's')
{