Вынес рендер в отдельный модуль. Сделал систему вызовов для модулй к ядру. Исправил баг в 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
-42
View File
@@ -1,42 +0,0 @@
name: Ubuntu test
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
BUILD_TYPE: Release
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository with submodules
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 1
- name: Проверка содержимого glfw
run: ls -la glfw
- name: Install dependencies (Wayland, X11, Vulkan, OpenGL)
run: |
sudo apt-get update
sudo apt-get install -y \
wayland-protocols libwayland-dev libxkbcommon-dev \
libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev \
libvulkan-dev mesa-common-dev
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
#- name: Test
# working-directory: ${{github.workspace}}/build
# run: ctest -C ${{env.BUILD_TYPE}}
+1
View File
@@ -20,5 +20,6 @@ add_subdirectory(FastRTTI)
add_subdirectory(glfw)
add_subdirectory(Core)
add_subdirectory(ModuleLib)
add_subdirectory(RenderModule)
add_subdirectory(TestGame)
add_subdirectory(ProjectGenerator)
+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"));
-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')
{
+23 -34
View File
@@ -3,14 +3,18 @@
#include <mutex>
#include <thread>
ModuleInstance::ModuleInstance(CoreInstance& core) : core_(core)
{
// Init instance
}
#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()
{
// Create thread
}
void ModuleInstance::stop()
@@ -18,51 +22,36 @@ void ModuleInstance::stop()
onStop.Call();
}
extern ModuleInstance* Factory(CoreInstance&);
static std::mutex mModuleInstance;
static ModuleInstance* module = nullptr;
static std::thread* moduleThread;
void InitModule(CoreInstance& core)
void ModuleInstance::QuitGame()
{
mModuleInstance.lock();
callbacks_->Quit();
}
void InitModule(CoreCallBacks* callbacks)
{
std::lock_guard<std::mutex> lock(mModuleInstance);
callbacks_ = callbacks;
if(module == nullptr)
module = Factory(core);
mModuleInstance.unlock();
module = Factory();
}
void StartModule()
{
mModuleInstance.lock();
std::lock_guard<std::mutex> lock(mModuleInstance);
if (module != nullptr)
moduleThread = new std::thread([&] {module->start(); });
mModuleInstance.unlock();
}
void StopModule()
{
mModuleInstance.lock();
if(module != nullptr)
{
delete module;
module = nullptr;
moduleThread->detach();
delete moduleThread;
}
mModuleInstance.unlock();
moduleThread = new std::thread(&ModuleInstance::start, module);
}
void QuitModule()
{
mModuleInstance.lock();
std::lock_guard<std::mutex> lock(mModuleInstance);
if(module != nullptr)
{
module->stop();
moduleThread->join();
delete module;
module = nullptr;
delete moduleThread;
moduleThread = nullptr;
}
mModuleInstance.unlock();
}
+5 -13
View File
@@ -17,39 +17,31 @@
extern "C" {\
EXPORT void* protect_init() {return reinterpret_cast<void*>(&InitModule);} \
EXPORT void* protect_start() {return reinterpret_cast<void*>(&StartModule);} \
EXPORT void* protect_stop() {return reinterpret_cast<void*>(&StopModule);} \
EXPORT void* protect_quit() {return reinterpret_cast<void*>(&QuitModule);} \
}\
ModuleInstance* Factory(CoreInstance& core) { return static_cast<ModuleInstance*>(new Class(core)); }
ModuleInstance* Factory() { return static_cast<ModuleInstance*>(new Class()); }
class CoreInstance;
struct CoreCallBacks;
class ModuleInstance {
CoreInstance& core_;
public:
Delegate<void> onStop;
ModuleInstance(CoreInstance& core);
virtual ~ModuleInstance() = default;
CoreInstance& getCore() const { return core_; }
virtual void start();
void stop();
void QuitGame();
};
extern "C" {
// Create module instance
EXPORT void InitModule(CoreInstance& core);
EXPORT void InitModule(CoreCallBacks* callbacks);
// Start module instance
EXPORT void StartModule();
// Destroy module instance when core unloads there
EXPORT void StopModule();
// Stop module when core calls this
EXPORT void QuitModule();
}
+23
View File
@@ -0,0 +1,23 @@
find_package(Vulkan REQUIRED)
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp")
add_library(RenderModule SHARED ${SRC})
target_compile_features(RenderModule PRIVATE cxx_std_17)
target_include_directories(RenderModule
PRIVATE
${PROJECT_SOURCE_DIR}/ModuleLib
${PROJECT_SOURCE_DIR}/Core
${PROJECT_SOURCE_DIR}/FastRTTI
${PROJECT_SOURCE_DIR}/Delegate
${PROJECT_SOURCE_DIR}/glfw/Include
${Vulkan_INCLUDE_DIRS}
)
target_link_libraries(RenderModule PRIVATE
ModuleLib
FastRTTI
glfw
Vulkan::Vulkan
)
@@ -2,9 +2,14 @@
#include <stdexcept>
#include <vector>
#include <string>
#include "Core/CoreInstance.h"
PROTECTION_FROM_GB(RenderEngine)
#ifdef _DEBUG
#include "Log/Log.h"
//#include "Log/Log.h"
#include <assert.h>
#define VK_CHECK(res) assert(res == VK_SUCCESS)
@@ -16,7 +21,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
std::string msg = "validation layer: ";
msg += pCallbackData->pMessage;
Log(msg);
//Log(msg);
return VK_FALSE;
}
@@ -42,33 +47,16 @@ std::vector<const char*> RenderEngine::get_required_extensions()
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)
RenderEngine::RenderEngine() : window(nullptr)
#ifdef _DEBUG
, debug_messenger_(nullptr)
#endif
{
if (!glfwInit())
throw std::runtime_error("Fail initialize GLFW");
onStop.bind(this, &RenderEngine::stop_render);
if (glfwInit() == GLFW_FALSE)
throw std::runtime_error("Fail init glfw");
{
std::vector<const char*> extensions = get_required_extensions();
std::vector<const char*> layers = {
@@ -80,10 +68,10 @@ RenderEngine::RenderEngine(const std::string& app_name,
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.applicationVersion = VK_MAKE_VERSION(0, 0, 0);
app_info.pApplicationName = "UwU Engine";
app_info.pEngineName = "UwU Engine";
app_info.engineVersion = VK_MAKE_VERSION(major_engine_version, minor_engine_version, patch_engine_version);
app_info.engineVersion = VK_MAKE_VERSION(0, 0, 0);
VkInstanceCreateInfo instance_create_info{};
@@ -123,15 +111,6 @@ RenderEngine::RenderEngine(const std::string& app_name,
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"));
@@ -149,5 +128,23 @@ RenderEngine::~RenderEngine()
void RenderEngine::start()
{
render_thread = new std::thread(&RenderEngine::render_thread_func, this);
window = glfwCreateWindow(640, 480, "UwU Engine", nullptr, nullptr);
if (!window)
{
glfwTerminate();
throw std::runtime_error("Fail create window");
}
while (!glfwWindowShouldClose(window))
{
glfwSwapBuffers(window);
glfwPollEvents();
}
QuitGame();
}
void RenderEngine::stop_render()
{
if (window != nullptr && !glfwWindowShouldClose(window))
glfwSetWindowShouldClose(window, true);
}
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#define GLFW_INCLUDE_VULKAN
#include "GLFW/glfw3.h"
#include "ModuleInstance.h"
#include <vector>
template<typename T>
class Delegate;
class RenderEngine : public ModuleInstance
{
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 stop_render();
public:
RenderEngine();
~RenderEngine() override;
void start() override;
};
+1 -1
View File
@@ -1 +1 @@
{"Class name":"MainConfig","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","vsmodules_names":["RenderModule"]}