Я пересоздал репозиторий из-за большого количества мусора в прошлом
This commit is contained in:
@@ -0,0 +1,34 @@
|
|||||||
|
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: 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}}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
name: Windows test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
BUILD_TYPE: Release
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: windows-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository with submodules
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
fetch-depth: 1
|
||||||
|
|
||||||
|
- name: Проверка содержимого glfw
|
||||||
|
run: dir glfw
|
||||||
|
|
||||||
|
- 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}}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
CMakeLists.txt.user
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
CMakeScripts
|
||||||
|
Testing
|
||||||
|
Makefile
|
||||||
|
cmake_install.cmake
|
||||||
|
install_manifest.txt
|
||||||
|
compile_commands.json
|
||||||
|
CTestTestfile.cmake
|
||||||
|
_deps
|
||||||
|
CMakeUserPresets.json
|
||||||
|
|
||||||
|
# CLion
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
#cmake-build-*
|
||||||
|
|
||||||
|
build/
|
||||||
|
.dist/
|
||||||
|
.vs/
|
||||||
|
.vscode/
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "glfw"]
|
||||||
|
path = glfw
|
||||||
|
url = https://github.com/glfw/glfw.git
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
project("UwU Engine" VERSION 0.1.0)
|
||||||
|
|
||||||
|
set(OUTPUT_DIR ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR})
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_DIR})
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OUTPUT_DIR})
|
||||||
|
|
||||||
|
if(NOT MSVC)
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
add_compile_options(/GR-)
|
||||||
|
else()
|
||||||
|
add_compile_options(-fno-rtti)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(FastRTTI)
|
||||||
|
add_subdirectory(glfw)
|
||||||
|
add_subdirectory(Core)
|
||||||
|
add_subdirectory(ModuleLib)
|
||||||
|
add_subdirectory(TestGame)
|
||||||
|
add_subdirectory(ProjectGenerator)
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
set(CORE_NAME Core)
|
||||||
|
|
||||||
|
find_package(Vulkan REQUIRED)
|
||||||
|
|
||||||
|
set(CORE_NAME Core)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp")
|
||||||
|
|
||||||
|
add_library(${CORE_NAME} STATIC ${SRC})
|
||||||
|
target_compile_features(${CORE_NAME} PRIVATE cxx_std_17)
|
||||||
|
target_include_directories(${CORE_NAME}
|
||||||
|
PRIVATE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${PROJECT_SOURCE_DIR}/FastRTTI
|
||||||
|
${PROJECT_SOURCE_DIR}/Delegate
|
||||||
|
${PROJECT_SOURCE_DIR}/glfw/Include
|
||||||
|
${Vulkan_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(${CORE_NAME} PRIVATE
|
||||||
|
${CMAKE_DL_LIBS} # For linux
|
||||||
|
FastRTTI
|
||||||
|
glfw
|
||||||
|
Vulkan::Vulkan
|
||||||
|
)
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
#include "CoreInstance.h"
|
||||||
|
|
||||||
|
#include "SystemCalls.h"
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> CoreInstance::MainConfig::save()
|
||||||
|
{
|
||||||
|
return std::make_shared<SaveMap>("MainConfig");
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreInstance::CoreInstance()
|
||||||
|
{
|
||||||
|
countCPU = System::getCountCPU();
|
||||||
|
memorySize = System::getMemorySize();
|
||||||
|
|
||||||
|
std::ifstream main_config_file(main_config_name);
|
||||||
|
if (main_config_file.fail())
|
||||||
|
throw std::runtime_error("Fail open main config file");
|
||||||
|
|
||||||
|
std::string payload;
|
||||||
|
std::getline(main_config_file, payload);
|
||||||
|
std::shared_ptr<SaveMap> load_main_config = std::make_shared<SaveMap>(payload);
|
||||||
|
|
||||||
|
main_config.load(load_main_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreInstance::~CoreInstance()
|
||||||
|
{
|
||||||
|
if (game != nullptr)
|
||||||
|
delete game;
|
||||||
|
|
||||||
|
for (auto& module : modules)
|
||||||
|
System::QuitModule(module.handler);
|
||||||
|
modules.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern GameInstance* GameFactory(CoreInstance&);
|
||||||
|
|
||||||
|
void CoreInstance::start()
|
||||||
|
{
|
||||||
|
for (auto& name : main_config.modules_names)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
void* handler = System::InitModule(name.c_str(), *this);
|
||||||
|
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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
game = GameFactory(*this);
|
||||||
|
if (game == nullptr)
|
||||||
|
throw std::runtime_error("Fail create game instance!");
|
||||||
|
game->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
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, *this);
|
||||||
|
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");
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include "Game/GameInstance.h"
|
||||||
|
#include "Game/SaveMap/SaveMap.h"
|
||||||
|
|
||||||
|
class CoreInstance {
|
||||||
|
struct Module {
|
||||||
|
const char* name;
|
||||||
|
void* handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MainConfig final : ISave
|
||||||
|
{
|
||||||
|
std::string game_name;
|
||||||
|
std::string base_world;
|
||||||
|
std::vector<std::string> modules_names;
|
||||||
|
|
||||||
|
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;
|
||||||
|
std::list<Module> modules;
|
||||||
|
|
||||||
|
GameInstance* game = nullptr;
|
||||||
|
public:
|
||||||
|
CoreInstance();
|
||||||
|
~CoreInstance();
|
||||||
|
|
||||||
|
void start();
|
||||||
|
|
||||||
|
int getCountCPU() const { return countCPU; }
|
||||||
|
unsigned long long getMemorySize() const { return memorySize; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
const std::string& getBaseWorldName() const { return main_config.base_world; }
|
||||||
|
const std::string& getGameName() const { return main_config.game_name; }
|
||||||
|
};
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
#include "SystemCalls.h"
|
||||||
|
|
||||||
|
#include <sys/sysinfo.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
int System::getCountCPU()
|
||||||
|
{
|
||||||
|
int num_cores = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
if(num_cores <= 0)
|
||||||
|
throw std::runtime_error("Fail get number of cores");
|
||||||
|
|
||||||
|
return num_cores;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long System::getMemorySize()
|
||||||
|
{
|
||||||
|
struct sysinfo info{};
|
||||||
|
if(sysinfo(&info) == -1)
|
||||||
|
std::runtime_error("Fail get system info");
|
||||||
|
return info.totalram;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* System::InitModule(const char* ModuleName, CoreInstance& core)
|
||||||
|
{
|
||||||
|
std::string fileName = "./lib";
|
||||||
|
fileName += ModuleName;
|
||||||
|
fileName += ".so";
|
||||||
|
|
||||||
|
void* handler = dlopen(fileName.c_str(), RTLD_NOW);
|
||||||
|
if(handler == nullptr)
|
||||||
|
throw std::runtime_error("Module not found");
|
||||||
|
|
||||||
|
void(*init)(CoreInstance&) = reinterpret_cast<void(*)(CoreInstance&)>(dlsym(handler, "InitModule"));
|
||||||
|
if(init == nullptr)
|
||||||
|
throw std::runtime_error("Module not contains InitModule");
|
||||||
|
init(core);
|
||||||
|
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void System::StartModule(void* handler)
|
||||||
|
{
|
||||||
|
void(*start)() = reinterpret_cast<void(*)()>(dlsym(handler, "StartModule"));
|
||||||
|
if(start == nullptr)
|
||||||
|
throw std::runtime_error("Module not contins StartModule");
|
||||||
|
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"));
|
||||||
|
if(quit == nullptr)
|
||||||
|
throw std::runtime_error("Module not contains QuitModule");
|
||||||
|
quit();
|
||||||
|
dlclose(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#include "RenderEngine.h"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#include <assert.h>
|
||||||
|
#define VK_CHECK(res) assert(res == VK_SUCCESS)
|
||||||
|
#else
|
||||||
|
#define VK_CHECK(res) res
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void RenderEngine::render_thread_func()
|
||||||
|
{
|
||||||
|
window = glfwCreateWindow(640, 480, "UwU Engine", NULL, NULL);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (!glfwInit())
|
||||||
|
throw std::runtime_error("Fail initialize GLFW");
|
||||||
|
|
||||||
|
{
|
||||||
|
uint32_t extensions_count = 0;
|
||||||
|
const char** extensions = glfwGetRequiredInstanceExtensions(&extensions_count);
|
||||||
|
|
||||||
|
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.ppEnabledExtensionNames = extensions;
|
||||||
|
instance_create_info.enabledExtensionCount = extensions_count;
|
||||||
|
instance_create_info.pApplicationInfo = &app_info;
|
||||||
|
VK_CHECK(vkCreateInstance(&instance_create_info, nullptr, &instance_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderEngine::~RenderEngine()
|
||||||
|
{
|
||||||
|
if (window != nullptr && !glfwWindowShouldClose(window))
|
||||||
|
glfwSetWindowShouldClose(window, true);
|
||||||
|
|
||||||
|
if (render_thread != nullptr)
|
||||||
|
{
|
||||||
|
render_thread->join();
|
||||||
|
delete render_thread;
|
||||||
|
}
|
||||||
|
if (window != nullptr)
|
||||||
|
glfwDestroyWindow(window);
|
||||||
|
glfwTerminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderEngine::start()
|
||||||
|
{
|
||||||
|
render_thread = new std::thread(&RenderEngine::render_thread_func, this);
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define GLFW_INCLUDE_VULKAN
|
||||||
|
|
||||||
|
#include "Delegate/Delegate.h"
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "GLFW/glfw3.h"
|
||||||
|
|
||||||
|
class RenderEngine
|
||||||
|
{
|
||||||
|
std::thread* render_thread;
|
||||||
|
|
||||||
|
GLFWwindow* window;
|
||||||
|
VkInstance instance_;
|
||||||
|
|
||||||
|
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();
|
||||||
|
};
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class CoreInstance;
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
/**
|
||||||
|
* @throws std::exception if the operation finished with failed
|
||||||
|
* @return count CPU
|
||||||
|
*/
|
||||||
|
int getCountCPU();
|
||||||
|
unsigned long long getMemorySize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load module and init handler
|
||||||
|
* @throws std::runtime_error if module not found
|
||||||
|
* @return module handler
|
||||||
|
*/
|
||||||
|
void* InitModule(const char* ModuleName, CoreInstance& core);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* @throws std::runtime_error if module not contains QuitModule function
|
||||||
|
*/
|
||||||
|
void QuitModule(void* handler) noexcept(false);
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#include "SystemCalls.h"
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <exception>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
int System::getCountCPU() {
|
||||||
|
DWORD len = 0;
|
||||||
|
GetLogicalProcessorInformation(nullptr, &len);
|
||||||
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||||
|
throw std::runtime_error(std::to_string(GetLastError()).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(len);
|
||||||
|
if (!GetLogicalProcessorInformation(buffer.data(), &len)) {
|
||||||
|
throw std::runtime_error(std::to_string(GetLastError()).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD count = len / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
|
||||||
|
int physicalCoreCount = 0;
|
||||||
|
|
||||||
|
for (DWORD i = 0; i < count; ++i) {
|
||||||
|
if (buffer[i].Relationship == RelationProcessorCore) {
|
||||||
|
physicalCoreCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return physicalCoreCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long System::getMemorySize() {
|
||||||
|
MEMORYSTATUSEX memStatus{};
|
||||||
|
memStatus.dwLength = sizeof(memStatus);
|
||||||
|
|
||||||
|
GlobalMemoryStatusEx(&memStatus);
|
||||||
|
return memStatus.ullTotalPhys;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* System::InitModule(const char* ModuleName, CoreInstance& core) {
|
||||||
|
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)(CoreInstance&) = reinterpret_cast<void(*)(CoreInstance&)>(GetProcAddress(hModule, "InitModule"));
|
||||||
|
if(load == nullptr) {
|
||||||
|
throw std::runtime_error(std::to_string(GetLastError()).c_str());
|
||||||
|
}
|
||||||
|
load(core);
|
||||||
|
|
||||||
|
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::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) {
|
||||||
|
throw std::runtime_error(std::to_string(GetLastError()).c_str());
|
||||||
|
}
|
||||||
|
quit();
|
||||||
|
FreeLibrary(static_cast<HMODULE>(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "CoreInstance.h"
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
try {
|
||||||
|
CoreInstance core;
|
||||||
|
std::cout << "CPU: " << core.getCountCPU() << std::endl;
|
||||||
|
std::cout << "Memory: " << core.getMemorySize() << std::endl;
|
||||||
|
core.start();
|
||||||
|
} catch(std::exception& e) {
|
||||||
|
std::cout << "[!] Unknown error (" << e.what() << ")\n";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
#include "CoreInstance.h"
|
||||||
|
|
||||||
|
#include "SystemCalls.h"
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
CoreInstance::CoreInstance()
|
||||||
|
{
|
||||||
|
countCPU = System::getCountCPU();
|
||||||
|
memorySize = System::getMemorySize();
|
||||||
|
|
||||||
|
std::ifstream main_config_file(main_config);
|
||||||
|
if (main_config_file.fail())
|
||||||
|
throw std::runtime_error("Fail open main config file");
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(main_config_file, line))
|
||||||
|
{
|
||||||
|
if (base_world.empty() && line.find(key_base_world) == 0)
|
||||||
|
{
|
||||||
|
size_t pos = line.find_first_of(':') + 1;
|
||||||
|
base_world = line.substr(pos, line.size() - pos);
|
||||||
|
// trim
|
||||||
|
while (base_world[0] == ' ')
|
||||||
|
base_world.erase(0, 1);
|
||||||
|
while (base_world[base_world.size() - 1] == ' ')
|
||||||
|
base_world.erase(base_world.size() - 2, base_world.size() - 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (modules_names.empty() && line.find(key_modules) == 0)
|
||||||
|
{
|
||||||
|
size_t pos = line.find(':') + 1;
|
||||||
|
line.erase(0, pos);
|
||||||
|
|
||||||
|
size_t end = line.find(',');
|
||||||
|
while (end != std::string::npos)
|
||||||
|
{
|
||||||
|
// trim
|
||||||
|
while (line[0] == ' ')
|
||||||
|
line.erase(0, 1);
|
||||||
|
std::string module_name = line.substr(0, end - 1);
|
||||||
|
// trim
|
||||||
|
while (module_name[module_name.size() - 1] == ' ')
|
||||||
|
module_name.erase(module_name.size() - 2, module_name.size() - 1);
|
||||||
|
|
||||||
|
modules_names.push_back(module_name);
|
||||||
|
line.erase(0, end);
|
||||||
|
end = line.find(',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base_world.empty())
|
||||||
|
throw std::runtime_error("Fail read base world name");
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreInstance::~CoreInstance()
|
||||||
|
{
|
||||||
|
if (game != nullptr)
|
||||||
|
delete game;
|
||||||
|
|
||||||
|
for (auto& module : modules)
|
||||||
|
System::QuitModule(module.handler);
|
||||||
|
modules.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern GameInstance* GameFactory(CoreInstance&);
|
||||||
|
|
||||||
|
void CoreInstance::start()
|
||||||
|
{
|
||||||
|
for (auto& name : modules_names)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
void* handler = System::InitModule(name.c_str(), *this);
|
||||||
|
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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
game = GameFactory(*this);
|
||||||
|
if (game == nullptr)
|
||||||
|
throw std::runtime_error("Fail create game instance!");
|
||||||
|
game->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
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, *this);
|
||||||
|
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");
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Game/GameInstance.h"
|
||||||
|
|
||||||
|
class CoreInstance {
|
||||||
|
struct Module {
|
||||||
|
const char* name;
|
||||||
|
void* handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
#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 = "main_config.conf";
|
||||||
|
std::string base_world;
|
||||||
|
std::vector<std::string> modules_names;
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
int countCPU;
|
||||||
|
unsigned long long memorySize;
|
||||||
|
std::list<Module> modules;
|
||||||
|
|
||||||
|
GameInstance* game = nullptr;
|
||||||
|
public:
|
||||||
|
CoreInstance();
|
||||||
|
~CoreInstance();
|
||||||
|
|
||||||
|
void start();
|
||||||
|
|
||||||
|
int getCountCPU() const { return countCPU; }
|
||||||
|
unsigned long long getMemorySize() const { return memorySize; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
const std::string& getBaseWorldName() const { return base_world; }
|
||||||
|
};
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
#include "SystemCalls.h"
|
||||||
|
|
||||||
|
#include <sys/sysinfo.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
int System::getCountCPU()
|
||||||
|
{
|
||||||
|
int num_cores = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
if(num_cores <= 0)
|
||||||
|
throw std::runtime_error("Fail get number of cores");
|
||||||
|
|
||||||
|
return num_cores;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long System::getMemorySize()
|
||||||
|
{
|
||||||
|
struct sysinfo info{};
|
||||||
|
if(sysinfo(&info) == -1)
|
||||||
|
std::runtime_error("Fail get system info");
|
||||||
|
return info.totalram;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* System::InitModule(const char* ModuleName, CoreInstance& core)
|
||||||
|
{
|
||||||
|
std::string fileName = "./lib";
|
||||||
|
fileName += ModuleName;
|
||||||
|
fileName += ".so";
|
||||||
|
|
||||||
|
void* handler = dlopen(fileName.c_str(), RTLD_NOW);
|
||||||
|
if(handler == nullptr)
|
||||||
|
throw std::runtime_error("Module not found");
|
||||||
|
|
||||||
|
void(*init)(CoreInstance&) = reinterpret_cast<void(*)(CoreInstance&)>(dlsym(handler, "InitModule"));
|
||||||
|
if(init == nullptr)
|
||||||
|
throw std::runtime_error("Module not contains InitModule");
|
||||||
|
init(core);
|
||||||
|
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void System::StartModule(void* handler)
|
||||||
|
{
|
||||||
|
void(*start)() = reinterpret_cast<void(*)()>(dlsym(handler, "StartModule"));
|
||||||
|
if(start == nullptr)
|
||||||
|
throw std::runtime_error("Module not contins StartModule");
|
||||||
|
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"));
|
||||||
|
if(quit == nullptr)
|
||||||
|
throw std::runtime_error("Module not contains QuitModule");
|
||||||
|
quit();
|
||||||
|
dlclose(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class CoreInstance;
|
||||||
|
|
||||||
|
namespace System {
|
||||||
|
/**
|
||||||
|
* @throws std::exception if the operation finished with failed
|
||||||
|
* @return count CPU
|
||||||
|
*/
|
||||||
|
int getCountCPU();
|
||||||
|
unsigned long long getMemorySize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load module and init handler
|
||||||
|
* @throws std::runtime_error if module not found
|
||||||
|
* @return module handler
|
||||||
|
*/
|
||||||
|
void* InitModule(const char* ModuleName, CoreInstance& core);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* @throws std::runtime_error if module not contains QuitModule function
|
||||||
|
*/
|
||||||
|
void QuitModule(void* handler) noexcept(false);
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#include "SystemCalls.h"
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <exception>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
int System::getCountCPU() {
|
||||||
|
DWORD len = 0;
|
||||||
|
GetLogicalProcessorInformation(nullptr, &len);
|
||||||
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||||
|
throw std::runtime_error(std::to_string(GetLastError()).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(len);
|
||||||
|
if (!GetLogicalProcessorInformation(buffer.data(), &len)) {
|
||||||
|
throw std::runtime_error(std::to_string(GetLastError()).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD count = len / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
|
||||||
|
int physicalCoreCount = 0;
|
||||||
|
|
||||||
|
for (DWORD i = 0; i < count; ++i) {
|
||||||
|
if (buffer[i].Relationship == RelationProcessorCore) {
|
||||||
|
physicalCoreCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return physicalCoreCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long System::getMemorySize() {
|
||||||
|
MEMORYSTATUSEX memStatus{};
|
||||||
|
memStatus.dwLength = sizeof(memStatus);
|
||||||
|
|
||||||
|
GlobalMemoryStatusEx(&memStatus);
|
||||||
|
return memStatus.ullTotalPhys;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* System::InitModule(const char* ModuleName, CoreInstance& core) {
|
||||||
|
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)(CoreInstance&) = reinterpret_cast<void(*)(CoreInstance&)>(GetProcAddress(hModule, "InitModule"));
|
||||||
|
if(load == nullptr) {
|
||||||
|
throw std::runtime_error(std::to_string(GetLastError()).c_str());
|
||||||
|
}
|
||||||
|
load(core);
|
||||||
|
|
||||||
|
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::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) {
|
||||||
|
throw std::runtime_error(std::to_string(GetLastError()).c_str());
|
||||||
|
}
|
||||||
|
quit();
|
||||||
|
FreeLibrary(static_cast<HMODULE>(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "CoreInstance/CoreInstance.h"
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
try {
|
||||||
|
CoreInstance core;
|
||||||
|
std::cout << "CPU: " << core.getCountCPU() << std::endl;
|
||||||
|
std::cout << "Memory: " << core.getMemorySize() << std::endl;
|
||||||
|
core.start();
|
||||||
|
} catch(std::exception& e) {
|
||||||
|
std::cout << "[!] Unknown error (" << e.what() << ")\n";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
#include "Actor.h"
|
||||||
|
|
||||||
|
#include "Game/SaveMap/SaveMap.h"
|
||||||
|
#include "Log/Log.h"
|
||||||
|
|
||||||
|
Actor::Actor()
|
||||||
|
{
|
||||||
|
SetType(Classes::Actor);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> Actor::save() noexcept
|
||||||
|
{
|
||||||
|
std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("Actor");
|
||||||
|
save->SaveObject("loc", &loc)
|
||||||
|
->SaveObject("rot", &rot)
|
||||||
|
->SaveObject("scale", &scale)
|
||||||
|
->SaveListStrings("tags", std::move(tags));
|
||||||
|
return save;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::load(std::shared_ptr<SaveMap> save) noexcept
|
||||||
|
{
|
||||||
|
loc = *reinterpret_cast<Vector3D*>(save->GetObject("loc"));
|
||||||
|
rot = *reinterpret_cast<Vector3D*>(save->GetObject("rot"));
|
||||||
|
scale = *reinterpret_cast<Vector3D*>(save->GetObject("scale"));
|
||||||
|
tags = std::move(save->GetListString("tags"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::BeginPlay()
|
||||||
|
{
|
||||||
|
Log("Actor::BeginPlay");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::Tick(double delta_time)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::SetActorLocate(const Vector3D& loc) noexcept
|
||||||
|
{
|
||||||
|
this->loc = loc;
|
||||||
|
OnSetActorLocate.Call(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::SetActorRotate(const Vector3D& rot) noexcept
|
||||||
|
{
|
||||||
|
this->rot = rot;
|
||||||
|
OnSetActorRotate.Call(rot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::AddTag(const std::string& tag) noexcept
|
||||||
|
{
|
||||||
|
tags.push_back(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::RemoveTag(const std::string& tag) noexcept
|
||||||
|
{
|
||||||
|
tags.remove(tag);
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#include "RTTI.h"
|
||||||
|
#include "RTTI_Meta.h"
|
||||||
|
#include "Game/SaveMap/ISave.h"
|
||||||
|
#include "Delegate/Delegate.h"
|
||||||
|
#include "Math/Vector.h"
|
||||||
|
|
||||||
|
GENERATE_META(Actor)
|
||||||
|
|
||||||
|
class Actor : public ISave, public IRTTI
|
||||||
|
{
|
||||||
|
Vector3D loc;
|
||||||
|
Vector3D rot;
|
||||||
|
Vector3D scale;
|
||||||
|
|
||||||
|
std::list<std::string> tags;
|
||||||
|
public:
|
||||||
|
Actor();
|
||||||
|
|
||||||
|
Delegate<const Vector3D&> OnSetActorLocate;
|
||||||
|
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;
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
virtual void BeginPlay();
|
||||||
|
virtual void Tick(double delta_time);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Изменяет положение в пространстве
|
||||||
|
* Вызывает делегат OnSetActorLocate
|
||||||
|
*/
|
||||||
|
void SetActorLocate(const Vector3D& loc) noexcept;
|
||||||
|
inline const Vector3D& GetActorLocate() const { return loc; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Изменяет ориентацию в пространстве
|
||||||
|
* Вызывает делегат OnSetActorRotate
|
||||||
|
*/
|
||||||
|
void SetActorRotate(const Vector3D& rot) noexcept;
|
||||||
|
inline const 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; }
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#include "ObjectFactory.h"
|
||||||
|
|
||||||
|
#include "Game/Actors/Actor.h"
|
||||||
|
#include "Math/Vector.h"
|
||||||
|
|
||||||
|
std::vector<ObjectFactory> base_object_factories = {
|
||||||
|
GENERATE_FACTORY_OBJECT(Actor)
|
||||||
|
GENERATE_FACTORY_OBJECT(Vector2D)
|
||||||
|
GENERATE_FACTORY_OBJECT(Vector3D)
|
||||||
|
};
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#include "GameInstance.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "Core/CoreInstance.h"
|
||||||
|
#include "Core/RenderEngine.h"
|
||||||
|
#include "Game/WorldFactory.h"
|
||||||
|
#include "SaveMap/SaveMap.h"
|
||||||
|
#include "Game/World/World.h"
|
||||||
|
|
||||||
|
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
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
world = factories.factory(*this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (world == nullptr)
|
||||||
|
throw std::runtime_error("Can't find world");
|
||||||
|
|
||||||
|
world->load(std::make_shared<SaveMap>(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
GameInstance::~GameInstance()
|
||||||
|
{
|
||||||
|
delete world;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameInstance::start()
|
||||||
|
{
|
||||||
|
render_engine_->start();
|
||||||
|
world->BeginPlay();
|
||||||
|
|
||||||
|
auto first = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
|
||||||
|
while (is_running)
|
||||||
|
{
|
||||||
|
auto second = std::chrono::steady_clock::now();
|
||||||
|
std::chrono::milliseconds delta_time = std::chrono::duration_cast<std::chrono::milliseconds>(second - first);
|
||||||
|
world->Tick(delta_time.count() / 1000.0);
|
||||||
|
first = second;
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameInstance::quit()
|
||||||
|
{
|
||||||
|
is_running = false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class CoreInstance;
|
||||||
|
class World;
|
||||||
|
class RenderEngine;
|
||||||
|
|
||||||
|
#define GENERATE_FACTORY_GAME_INSTANCE(Class) \
|
||||||
|
GameInstance* GameFactory(CoreInstance& core) { return new Class(core); }
|
||||||
|
|
||||||
|
class GameInstance
|
||||||
|
{
|
||||||
|
CoreInstance& core;
|
||||||
|
World* world = nullptr;
|
||||||
|
std::unique_ptr<RenderEngine> render_engine_;
|
||||||
|
|
||||||
|
std::atomic<bool> is_running = true;
|
||||||
|
|
||||||
|
// Create a window
|
||||||
|
// Render
|
||||||
|
// Pull events
|
||||||
|
void start();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void quit();
|
||||||
|
|
||||||
|
// Init vulkan
|
||||||
|
GameInstance(CoreInstance& core);
|
||||||
|
virtual ~GameInstance();
|
||||||
|
|
||||||
|
World* GetWorld() const { return world; }
|
||||||
|
|
||||||
|
friend class CoreInstance;
|
||||||
|
};
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class ISave;
|
||||||
|
|
||||||
|
struct ObjectFactory
|
||||||
|
{
|
||||||
|
const char* name;
|
||||||
|
ISave*(*factory)();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Создаёт список фабрик объектов
|
||||||
|
#define FACTORIES_LIST std::vector<ObjectFactory> factories =
|
||||||
|
|
||||||
|
// Создаёт фабрику для класса
|
||||||
|
#define GENERATE_FACTORY_OBJECT(Class) ObjectFactory{#Class, []()->ISave* { return new Class(); }},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Все классы или их родители в этом списке
|
||||||
|
* должны реализовывать инетфейс ISave.
|
||||||
|
* Пример использования:
|
||||||
|
|
||||||
|
FACTORIES_LIST {
|
||||||
|
GENERATE_FACTORY_OBJECT(SometimeClass_One)
|
||||||
|
GENERATE_FACTORY_OBJECT(SometimeClass_Two)
|
||||||
|
};
|
||||||
|
*/
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "RTTI_Meta.h"
|
||||||
|
|
||||||
|
GENERATE_META(IResource);
|
||||||
|
class IResource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual std::string serialize() = 0;
|
||||||
|
virtual void deserialize(const std::string& data) = 0;
|
||||||
|
};
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
#include "Resource.h"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
std::mutex Resource::mStringResource;
|
||||||
|
const char* Resource::StringResources = "./Resources/string.res";
|
||||||
|
|
||||||
|
std::mutex Resource::mIntResource;
|
||||||
|
const char* Resource::IntResources = "./Resources/int.res";
|
||||||
|
|
||||||
|
std::mutex Resource::mLongResource;
|
||||||
|
const char* Resource::LongResources = "./Resources/long.res";
|
||||||
|
|
||||||
|
std::mutex Resource::mDoubleResource;
|
||||||
|
const char* Resource::DoubleResources = "./Resources/double.res";
|
||||||
|
|
||||||
|
std::mutex Resource::mObjectResource;
|
||||||
|
const char* Resource::ObjectResources = "./Resources/object.res";
|
||||||
|
|
||||||
|
std::string Resource::GetResourceData(const char* name, const char* file_name)
|
||||||
|
{
|
||||||
|
size_t size_name = strlen(name);
|
||||||
|
std::ifstream file(file_name);
|
||||||
|
if (!file.is_open())
|
||||||
|
throw std::runtime_error("Can't open resource file");
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(file, line))
|
||||||
|
{
|
||||||
|
if (line.find(name) == 0 && line[size_name] == ':')
|
||||||
|
{
|
||||||
|
size_t begin = size_name + 2;
|
||||||
|
file.close();
|
||||||
|
return line.substr(begin, line.length() - begin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
throw std::runtime_error("Can't find resource");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resource::WriteResource(const char* name, const char* file_name, const std::string& value)
|
||||||
|
{
|
||||||
|
size_t size_name = strlen(name);
|
||||||
|
bool isFind = false;
|
||||||
|
std::string buffer;
|
||||||
|
std::ifstream file(file_name);
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(file, line))
|
||||||
|
{
|
||||||
|
if (line.find(name) == 0 && line[size_name] == ':')
|
||||||
|
{
|
||||||
|
isFind = true;
|
||||||
|
line.resize(size_name + 2 + value.length());
|
||||||
|
line.replace(size_name + 2, value.length(), value);
|
||||||
|
}
|
||||||
|
buffer += line + '\n';
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
if (!isFind)
|
||||||
|
{
|
||||||
|
buffer += name;
|
||||||
|
buffer += ": ";
|
||||||
|
buffer += value;
|
||||||
|
buffer += '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream drop_file(file_name, std::ios::trunc);
|
||||||
|
drop_file << buffer;
|
||||||
|
drop_file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resource::SetString(const char* name, const char* value)
|
||||||
|
{
|
||||||
|
mStringResource.lock();
|
||||||
|
WriteResource(name, StringResources, std::string(value));
|
||||||
|
mStringResource.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resource::SetInt(const char* name, int value)
|
||||||
|
{
|
||||||
|
mIntResource.lock();
|
||||||
|
WriteResource(name, IntResources, std::to_string(value));
|
||||||
|
mIntResource.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resource::SetLong(const char* name, long long value)
|
||||||
|
{
|
||||||
|
mLongResource.lock();
|
||||||
|
WriteResource(name, LongResources, std::to_string(value));
|
||||||
|
mLongResource.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resource::SetDouble(const char* name, double value)
|
||||||
|
{
|
||||||
|
mDoubleResource.lock();
|
||||||
|
WriteResource(name, DoubleResources, std::to_string(value));
|
||||||
|
mDoubleResource.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resource::SetObject(const char* name, IResource* object)
|
||||||
|
{
|
||||||
|
mObjectResource.lock();
|
||||||
|
WriteResource(name, ObjectResources, object->serialize());
|
||||||
|
mObjectResource.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Resource::GetString(const char* name)
|
||||||
|
{
|
||||||
|
mStringResource.lock();
|
||||||
|
std::string data = GetResourceData(name, StringResources);
|
||||||
|
mStringResource.unlock();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Resource::GetInt(const char* name)
|
||||||
|
{
|
||||||
|
mIntResource.lock();
|
||||||
|
int data = std::stoi(GetResourceData(name, IntResources));
|
||||||
|
mIntResource.unlock();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
long long Resource::GetLong(const char* name)
|
||||||
|
{
|
||||||
|
mLongResource.lock();
|
||||||
|
long long data = std::stoll(GetResourceData(name, LongResources));
|
||||||
|
mLongResource.unlock();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Resource::GetDouble(const char* name)
|
||||||
|
{
|
||||||
|
mDoubleResource.lock();
|
||||||
|
double data = std::stod(GetResourceData(name, DoubleResources));
|
||||||
|
mDoubleResource.unlock();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IResource.h"
|
||||||
|
#include <mutex>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Resource final
|
||||||
|
{
|
||||||
|
static std::mutex mStringResource;
|
||||||
|
static const char* StringResources;
|
||||||
|
|
||||||
|
static std::mutex mIntResource;
|
||||||
|
static const char* IntResources;
|
||||||
|
|
||||||
|
static std::mutex mLongResource;
|
||||||
|
static const char* LongResources;
|
||||||
|
|
||||||
|
static std::mutex mDoubleResource;
|
||||||
|
static const char* DoubleResources;
|
||||||
|
|
||||||
|
static std::mutex mObjectResource;
|
||||||
|
static const char* ObjectResources;
|
||||||
|
|
||||||
|
// throw: std::runtime_error("Can't find resource") если ресурса не существует
|
||||||
|
static std::string GetResourceData(const char* name, const char* file_name);
|
||||||
|
|
||||||
|
static void WriteResource(const char* name, const char* file_name, const std::string& value);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* Устанавливает значение в ресурс
|
||||||
|
* Не бросают исключений
|
||||||
|
*/
|
||||||
|
static void SetString(const char* name, const char* value);
|
||||||
|
static void SetInt(const char* name, int value);
|
||||||
|
static void SetLong(const char* name, long long value);
|
||||||
|
static void SetDouble(const char* name, double value);
|
||||||
|
static void SetObject(const char* name, IResource* object);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Метуды получения значений по ключу
|
||||||
|
* throw: std::runtime_error("Can't find resource") если ресурса не существует
|
||||||
|
*/
|
||||||
|
static std::string GetString(const char* name);
|
||||||
|
static int GetInt(const char* name);
|
||||||
|
static long long GetLong(const char* name);
|
||||||
|
static double GetDouble(const char* name);
|
||||||
|
template<class T>
|
||||||
|
static T* GetObject(const char* name)
|
||||||
|
{
|
||||||
|
mObjectResource.lock();
|
||||||
|
std::string data = GetResourceData(name, ObjectResources);
|
||||||
|
mObjectResource.unlock();
|
||||||
|
T* object = new T();
|
||||||
|
object->deserialize(data);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class SaveMap;
|
||||||
|
|
||||||
|
class ISave
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~ISave() = default;
|
||||||
|
virtual std::shared_ptr<SaveMap> save() = 0;
|
||||||
|
virtual void load(std::shared_ptr<SaveMap> save) = 0;
|
||||||
|
};
|
||||||
@@ -0,0 +1,587 @@
|
|||||||
|
#include "SaveMap.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include "Game/ObjectFactory.h"
|
||||||
|
|
||||||
|
extern std::vector<ObjectFactory> factories;
|
||||||
|
extern std::vector<ObjectFactory> base_object_factories;
|
||||||
|
|
||||||
|
ISave* SaveMap::MakeObjectByName(const std::string& name)
|
||||||
|
{
|
||||||
|
for (ObjectFactory& factory : base_object_factories)
|
||||||
|
{
|
||||||
|
if (name == factory.name) {
|
||||||
|
return factory.factory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (ObjectFactory& factory : factories)
|
||||||
|
{
|
||||||
|
if (name == factory.name) {
|
||||||
|
return factory.factory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("Object not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveMap::SaveMap(const char* class_name) : class_name(class_name)
|
||||||
|
{
|
||||||
|
if (class_name == nullptr)
|
||||||
|
throw std::runtime_error("Can't create save map with null name");
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveMap::SaveMap(const std::string& json_data)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < json_data.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);
|
||||||
|
|
||||||
|
std::string name = json_data.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);
|
||||||
|
i++;
|
||||||
|
class_name = json_data.substr(begin, end - begin);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name[0] == 'i') {
|
||||||
|
size_t begin = json_data.find(':', i) + 1;
|
||||||
|
size_t end = i = json_data.find_first_of(",}", i);
|
||||||
|
i++;
|
||||||
|
std::string value = json_data.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) + 1;
|
||||||
|
size_t end = i = json_data.find_first_of(",}", i);
|
||||||
|
i++;
|
||||||
|
std::string value = json_data.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);
|
||||||
|
i++;
|
||||||
|
std::string value = json_data.substr(begin, end - begin);
|
||||||
|
save_string[name.c_str() + 1] = value;
|
||||||
|
} else if (name[0] == 'o')
|
||||||
|
{
|
||||||
|
size_t begin = i = json_data.find('{', i);
|
||||||
|
int open = 1, close = 0;
|
||||||
|
while (close < open)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
if (json_data[i] == '{')
|
||||||
|
open++;
|
||||||
|
else if (json_data[i] == '}')
|
||||||
|
close++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t end = i;
|
||||||
|
i++;
|
||||||
|
|
||||||
|
std::string object_json = json_data.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);
|
||||||
|
|
||||||
|
object_ptr->load(std::make_shared<SaveMap>(object_json));
|
||||||
|
save_objects[name.c_str() + 1] = object_ptr;
|
||||||
|
} else if (name[0] == 'v')
|
||||||
|
{
|
||||||
|
std::string key = name.substr(2, name.length() - 2);
|
||||||
|
|
||||||
|
size_t begin_arr = i = json_data.find('[', i);
|
||||||
|
int open = 1, close = 0;
|
||||||
|
while (close < open)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
if (json_data[i] == '[')
|
||||||
|
open++;
|
||||||
|
else if (json_data[i] == ']')
|
||||||
|
close++;
|
||||||
|
}
|
||||||
|
size_t end_arr = i;
|
||||||
|
i++;
|
||||||
|
|
||||||
|
std::string arr_data = json_data.substr(begin_arr, end_arr - begin_arr + 1);
|
||||||
|
if (name[1] == 'i')
|
||||||
|
{
|
||||||
|
save_vector_integer[key] = std::vector<long long>();
|
||||||
|
if (arr_data.length() == 2)
|
||||||
|
continue;
|
||||||
|
std::vector<long long>& vector_integer = save_vector_integer[key];
|
||||||
|
|
||||||
|
size_t j = 1;
|
||||||
|
while (j < arr_data.length())
|
||||||
|
{
|
||||||
|
size_t end_val = arr_data.find_first_of(",]", j);
|
||||||
|
vector_integer.push_back(std::stoll(arr_data.substr(j, end_val - j)));
|
||||||
|
j = end_val + 1;
|
||||||
|
}
|
||||||
|
} else if (name[1] == 'd')
|
||||||
|
{
|
||||||
|
save_vector_double[key] = std::vector<double>();
|
||||||
|
if (arr_data.length() == 2)
|
||||||
|
continue;
|
||||||
|
std::vector<double>& vector_double = save_vector_double[key];
|
||||||
|
|
||||||
|
size_t j = 1;
|
||||||
|
while (j < arr_data.length())
|
||||||
|
{
|
||||||
|
size_t end_val = arr_data.find_first_of(",]", j);
|
||||||
|
vector_double.push_back(std::stod(arr_data.substr(j, end_val - j)));
|
||||||
|
j = end_val + 1;
|
||||||
|
}
|
||||||
|
} else if (name[1] == 's')
|
||||||
|
{
|
||||||
|
save_vector_strings[key] = std::vector<std::string>();
|
||||||
|
if (arr_data.length() == 2)
|
||||||
|
continue;
|
||||||
|
std::vector<std::string>& vector_strings = save_vector_strings[key];
|
||||||
|
|
||||||
|
size_t j = 2;
|
||||||
|
while (j < arr_data.length())
|
||||||
|
{
|
||||||
|
size_t begin = j;
|
||||||
|
size_t end = j = arr_data.find('\"', begin + 1);
|
||||||
|
std::string value = arr_data.substr(begin, end - begin);
|
||||||
|
vector_strings.push_back(value);
|
||||||
|
j += 3;
|
||||||
|
}
|
||||||
|
} else if (name[1] == 'o')
|
||||||
|
{
|
||||||
|
save_vector_objects[key] = std::vector<ISave*>();
|
||||||
|
if (arr_data.length() == 2)
|
||||||
|
continue;
|
||||||
|
std::vector<ISave*>& vector_object = save_vector_objects[key];
|
||||||
|
|
||||||
|
size_t j = 1;
|
||||||
|
while (j < arr_data.length())
|
||||||
|
{
|
||||||
|
size_t beg_val = j;
|
||||||
|
open = 1;
|
||||||
|
close = 0;
|
||||||
|
while (close < open)
|
||||||
|
{
|
||||||
|
j++;
|
||||||
|
if (arr_data[j] == '{')
|
||||||
|
open++;
|
||||||
|
else if (arr_data[j] == '}')
|
||||||
|
close++;
|
||||||
|
}
|
||||||
|
size_t end_val = j;
|
||||||
|
j++;
|
||||||
|
std::string object_json = arr_data.substr(beg_val, end_val - beg_val + 1);
|
||||||
|
|
||||||
|
size_t begin_name = object_json.find(':') + 2;
|
||||||
|
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);
|
||||||
|
|
||||||
|
object_ptr->load(std::make_shared<SaveMap>(object_json));
|
||||||
|
vector_object.push_back(object_ptr);
|
||||||
|
|
||||||
|
j = arr_data.find_first_of(",]", j) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (name[0] == 'l')
|
||||||
|
{
|
||||||
|
std::string key = name.substr(2, name.length() - 2);
|
||||||
|
|
||||||
|
size_t begin_arr = i = json_data.find('[', i);
|
||||||
|
int open = 1, close = 0;
|
||||||
|
while (close < open)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
if (json_data[i] == '[')
|
||||||
|
open++;
|
||||||
|
else if (json_data[i] == ']')
|
||||||
|
close++;
|
||||||
|
}
|
||||||
|
size_t end_arr = i;
|
||||||
|
i++;
|
||||||
|
|
||||||
|
std::string arr_data = json_data.substr(begin_arr, end_arr - begin_arr + 1);
|
||||||
|
if (name[1] == 'i')
|
||||||
|
{
|
||||||
|
save_list_integer[key] = std::list<long long>();
|
||||||
|
if (arr_data.length() == 2)
|
||||||
|
continue;
|
||||||
|
std::list<long long>& list_integer = save_list_integer[key];
|
||||||
|
|
||||||
|
size_t j = 1;
|
||||||
|
while (j < arr_data.length())
|
||||||
|
{
|
||||||
|
size_t end_val = arr_data.find_first_of(",]", j);
|
||||||
|
list_integer.push_back(std::stoll(arr_data.substr(j, end_val - j)));
|
||||||
|
j = end_val + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (name[1] == 'd')
|
||||||
|
{
|
||||||
|
save_list_double[key] = std::list<double>();
|
||||||
|
if (arr_data.length() == 2)
|
||||||
|
continue;
|
||||||
|
std::list<double>& list_double = save_list_double[key];
|
||||||
|
|
||||||
|
size_t j = 1;
|
||||||
|
while (j < arr_data.length())
|
||||||
|
{
|
||||||
|
size_t end_val = arr_data.find_first_of(",]", j);
|
||||||
|
list_double.push_back(std::stod(arr_data.substr(j, end_val - j)));
|
||||||
|
j = end_val + 1;
|
||||||
|
}
|
||||||
|
} else if (name[1] == 's')
|
||||||
|
{
|
||||||
|
save_list_strings[key] = std::list<std::string>();
|
||||||
|
if (arr_data.length() == 2)
|
||||||
|
continue;
|
||||||
|
std::list<std::string>& list_strings = save_list_strings[key];
|
||||||
|
|
||||||
|
size_t j = 2;
|
||||||
|
while (j < arr_data.length())
|
||||||
|
{
|
||||||
|
size_t begin = j;
|
||||||
|
size_t end = j = arr_data.find('\"', begin + 1);
|
||||||
|
std::string value = arr_data.substr(begin, end - begin);
|
||||||
|
list_strings.push_back(value);
|
||||||
|
j += 3;
|
||||||
|
}
|
||||||
|
} else if (name[1] == 'o')
|
||||||
|
{
|
||||||
|
save_list_objects[key] = std::list<ISave*>();
|
||||||
|
if (arr_data.length() == 2)
|
||||||
|
continue;
|
||||||
|
std::list<ISave*>& list_object = save_list_objects[key];
|
||||||
|
|
||||||
|
size_t j = 1;
|
||||||
|
while (j < arr_data.length())
|
||||||
|
{
|
||||||
|
size_t beg_val = j;
|
||||||
|
open = 1;
|
||||||
|
close = 0;
|
||||||
|
while (close < open)
|
||||||
|
{
|
||||||
|
j++;
|
||||||
|
if (arr_data[j] == '{')
|
||||||
|
open++;
|
||||||
|
else if (arr_data[j] == '}')
|
||||||
|
close++;
|
||||||
|
}
|
||||||
|
size_t end_val = j;
|
||||||
|
j++;
|
||||||
|
std::string object_json = arr_data.substr(beg_val, end_val - beg_val + 1);
|
||||||
|
|
||||||
|
size_t begin_name = object_json.find(':') + 2;
|
||||||
|
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);
|
||||||
|
|
||||||
|
object_ptr->load(std::make_shared<SaveMap>(object_json));
|
||||||
|
list_object.push_back(object_ptr);
|
||||||
|
|
||||||
|
j = arr_data.find_first_of(",]", j) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (name == "Parent parameters") {
|
||||||
|
size_t parent_begin = i = json_data.find('{', i);
|
||||||
|
int open = 1, close = 0;
|
||||||
|
while (close < open)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
if (json_data[i] == '{')
|
||||||
|
open++;
|
||||||
|
else if (json_data[i] == '}')
|
||||||
|
close++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t parent_end = i;
|
||||||
|
i++;
|
||||||
|
|
||||||
|
std::string str = json_data.substr(parent_begin, parent_end - parent_begin + 1);
|
||||||
|
parent = std::make_shared<SaveMap>(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> SaveMap::SaveInteger(const char* name, int value) noexcept
|
||||||
|
{
|
||||||
|
save_long[name] = value;
|
||||||
|
return std::shared_ptr<SaveMap>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> SaveMap::SaveDouble(const char* name, double value) noexcept
|
||||||
|
{
|
||||||
|
save_double[name] = value;
|
||||||
|
return std::shared_ptr<SaveMap>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> SaveMap::SaveString(const char* name, const std::string& value) noexcept
|
||||||
|
{
|
||||||
|
save_string[name] = value;
|
||||||
|
return std::shared_ptr<SaveMap>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> SaveMap::SaveObject(const char* name, ISave* object) noexcept
|
||||||
|
{
|
||||||
|
save_objects[name] = object;
|
||||||
|
return std::shared_ptr<SaveMap>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> SaveMap::SaveVectorInteger(const char* name, std::vector<long long>&& value) noexcept
|
||||||
|
{
|
||||||
|
save_vector_integer[name] = std::move(value);
|
||||||
|
return std::shared_ptr<SaveMap>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> SaveMap::SaveVectorDouble(const char* name, std::vector<double>&& value) noexcept
|
||||||
|
{
|
||||||
|
save_vector_double[name] = std::move(value);
|
||||||
|
return std::shared_ptr<SaveMap>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> SaveMap::SaveVectorStrings(const char* name, std::vector<std::string>&& value) noexcept
|
||||||
|
{
|
||||||
|
save_vector_strings[name] = std::move(value);
|
||||||
|
return std::shared_ptr<SaveMap>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> SaveMap::SaveVectorObject(const char* name, std::vector<ISave*>&& value) noexcept
|
||||||
|
{
|
||||||
|
save_vector_objects[name] = std::move(value);
|
||||||
|
return std::shared_ptr<SaveMap>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> SaveMap::SaveListInteger(const char* name, std::list<long long>&& value) noexcept
|
||||||
|
{
|
||||||
|
save_list_integer[name] = std::move(value);
|
||||||
|
return std::shared_ptr<SaveMap>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> SaveMap::SaveListDouble(const char* name, std::list<double>&& value) noexcept
|
||||||
|
{
|
||||||
|
save_list_double[name] = std::move(value);
|
||||||
|
return std::shared_ptr<SaveMap>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> SaveMap::SaveListStrings(const char* name, std::list<std::string>&& value) noexcept
|
||||||
|
{
|
||||||
|
save_list_strings[name] = std::move(value);
|
||||||
|
return std::shared_ptr<SaveMap>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> SaveMap::SaveListObject(const char* name, std::list<ISave*>&& value) noexcept
|
||||||
|
{
|
||||||
|
save_list_objects[name] = std::move(value);
|
||||||
|
return std::shared_ptr<SaveMap>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
long long SaveMap::GetInteger(const char* name)
|
||||||
|
{
|
||||||
|
return save_long[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
double SaveMap::GetDouble(const char* name)
|
||||||
|
{
|
||||||
|
return save_double[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* SaveMap::GetString(const char* name)
|
||||||
|
{
|
||||||
|
return save_string[name].c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
ISave* SaveMap::GetObject(const char* name)
|
||||||
|
{
|
||||||
|
return save_objects[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<long long>& SaveMap::GetVectorInteger(const char* name)
|
||||||
|
{
|
||||||
|
return save_vector_integer[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<double>& SaveMap::GetVectorDouble(const char* name)
|
||||||
|
{
|
||||||
|
return save_vector_double[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> SaveMap::GetVectorString(const char* name)
|
||||||
|
{
|
||||||
|
return save_vector_strings[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ISave*>& SaveMap::GetVectorObject(const char* name)
|
||||||
|
{
|
||||||
|
return save_vector_objects[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<long long>& SaveMap::GetListInteger(const char* name)
|
||||||
|
{
|
||||||
|
return save_list_integer[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<double>& SaveMap::GetListDouble(const char* name)
|
||||||
|
{
|
||||||
|
return save_list_double[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<std::string>& SaveMap::GetListString(const char* name)
|
||||||
|
{
|
||||||
|
return save_list_strings[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<ISave*>& SaveMap::GetListObject(const char* name)
|
||||||
|
{
|
||||||
|
return save_list_objects[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SaveMap::serialize() noexcept
|
||||||
|
{
|
||||||
|
std::string buffer = R"({"Class name":")" + class_name + '\"';
|
||||||
|
|
||||||
|
for (auto& [key, value] : save_long)
|
||||||
|
buffer += ",\"i" + key + "\":" + std::to_string(value);
|
||||||
|
|
||||||
|
for (auto& [key, value] : save_double)
|
||||||
|
buffer += ",\"d" + key + "\":" + std::to_string(value);
|
||||||
|
|
||||||
|
for (auto& [key, value] : save_string)
|
||||||
|
buffer += ",\"s" + key + "\":\"" + value + '\"';
|
||||||
|
|
||||||
|
for (auto& [key, value] : save_objects)
|
||||||
|
buffer += ",\"o" + key + "\":\"" + value->save()->serialize();
|
||||||
|
|
||||||
|
for (auto& [key, value] : save_vector_integer)
|
||||||
|
{
|
||||||
|
if (value.empty())
|
||||||
|
{
|
||||||
|
buffer += ",\"vi" + key + "\":[]";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buffer += ",\"vi" + key + "\":[";
|
||||||
|
for (auto& item : value)
|
||||||
|
buffer += std::to_string(item) + ',';
|
||||||
|
buffer.replace(buffer.length() - 1, buffer.length() - 1, "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& [key, value] : save_vector_double)
|
||||||
|
{
|
||||||
|
if (value.empty())
|
||||||
|
{
|
||||||
|
buffer += ",\"vd" + key + "\":[]";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buffer += ",\"vd" + key + "\":[";
|
||||||
|
for (auto& item : value)
|
||||||
|
buffer += std::to_string(item) + ',';
|
||||||
|
buffer.replace(buffer.length() - 1, buffer.length() - 1, "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& [key, value] : save_vector_objects)
|
||||||
|
{
|
||||||
|
if (value.empty())
|
||||||
|
{
|
||||||
|
buffer += ",\"vo" + key + "\":[]";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buffer += ",\"vo" + key + "\":[";
|
||||||
|
for (auto& item : value)
|
||||||
|
buffer += item->save()->serialize() + ',';
|
||||||
|
buffer.replace(buffer.length() - 1, buffer.length() - 1, "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& [key, value] : save_vector_strings)
|
||||||
|
{
|
||||||
|
if (value.empty())
|
||||||
|
{
|
||||||
|
buffer += ",\"vs" + key + "\":[]";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buffer += ",\"vs" + key + "\":[";
|
||||||
|
for (auto& item : value)
|
||||||
|
buffer += '\"' + item + "\",";
|
||||||
|
buffer.replace(buffer.length() - 1, buffer.length() - 1, "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& [key, value] : save_list_integer)
|
||||||
|
{
|
||||||
|
if (value.empty())
|
||||||
|
{
|
||||||
|
buffer += ",\"li" + key + "\":[]";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buffer += ",\"li" + key + "\":[";
|
||||||
|
for (auto& item : value)
|
||||||
|
buffer += std::to_string(item) + ',';
|
||||||
|
buffer.replace(buffer.length() - 1, buffer.length() - 1, "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& [key, value] : save_list_double)
|
||||||
|
{
|
||||||
|
if (value.empty())
|
||||||
|
{
|
||||||
|
buffer += ",\"ld" + key + "\":[]";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buffer += ",\"ld" + key + "\":[";
|
||||||
|
for (auto& item : value)
|
||||||
|
buffer += std::to_string(item) + ',';
|
||||||
|
buffer.replace(buffer.length() - 1, buffer.length() - 1, "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& [key, value] : save_list_objects)
|
||||||
|
{
|
||||||
|
if (value.empty())
|
||||||
|
{
|
||||||
|
buffer += ",\"lo" + key + "\":[]";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buffer += ",\"lo" + key + "\":[";
|
||||||
|
for (auto& item : value)
|
||||||
|
buffer += item->save()->serialize() + ',';
|
||||||
|
buffer.replace(buffer.length() - 1, buffer.length() - 1, "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& [key, value] : save_list_strings)
|
||||||
|
{
|
||||||
|
if (value.empty())
|
||||||
|
{
|
||||||
|
buffer += ",\"ls" + key + "\":[]";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
buffer += ",\"ls" + key + "\":[";
|
||||||
|
for (auto& item : value)
|
||||||
|
buffer += '\"' + item + "\",";
|
||||||
|
buffer.replace(buffer.length() - 1, buffer.length() - 1, "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent != nullptr) {
|
||||||
|
buffer += ",\"Parent parameters\":" + parent->serialize() + '}';
|
||||||
|
} else
|
||||||
|
buffer += '}';
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveMap* SaveMap::connect_to(std::shared_ptr<SaveMap> parent)
|
||||||
|
{
|
||||||
|
if (this->parent != nullptr)
|
||||||
|
throw std::runtime_error("Can't connect to second parent");
|
||||||
|
|
||||||
|
this->parent = parent;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ISave.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
class SaveMap final
|
||||||
|
{
|
||||||
|
std::string class_name;
|
||||||
|
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::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::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;
|
||||||
|
|
||||||
|
static ISave* MakeObjectByName(const std::string& name);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Создаёт пустой объект для заполнения
|
||||||
|
SaveMap(const char* class_name);
|
||||||
|
// Токенезирут JSON строку
|
||||||
|
SaveMap(const std::string& json_data);
|
||||||
|
|
||||||
|
// Методы созранения значений
|
||||||
|
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> 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> 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;
|
||||||
|
|
||||||
|
// Методы получения значенй
|
||||||
|
long long GetInteger(const char* name);
|
||||||
|
double GetDouble(const char* name);
|
||||||
|
const char* GetString(const char* name);
|
||||||
|
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::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::shared_ptr<SaveMap> getParent() const { return parent; }
|
||||||
|
const std::string& getClassName() const { return class_name; }
|
||||||
|
|
||||||
|
// Собирает все токены в JSON объект
|
||||||
|
std::string serialize() noexcept;
|
||||||
|
|
||||||
|
SaveMap* connect_to(std::shared_ptr<SaveMap> parent);
|
||||||
|
};
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#include "World.h"
|
||||||
|
|
||||||
|
#include "Game/SaveMap/SaveMap.h"
|
||||||
|
|
||||||
|
World::World(GameInstance& game_instance) : game_instance(game_instance)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
World::~World()
|
||||||
|
{
|
||||||
|
for (auto& actor : actors)
|
||||||
|
delete actor;
|
||||||
|
actors.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::BeginPlay()
|
||||||
|
{
|
||||||
|
for (auto& i : actors)
|
||||||
|
i->BeginPlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::Tick(double delta_time)
|
||||||
|
{
|
||||||
|
for (auto& i : actors)
|
||||||
|
i->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")));
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class GameInstance;
|
||||||
|
class World;
|
||||||
|
|
||||||
|
struct WorldFactory
|
||||||
|
{
|
||||||
|
const char* world_name;
|
||||||
|
World*(*factory)(GameInstance&);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Создаёт ассоцеативный список
|
||||||
|
// В нём соспоставляются имина уровней и фабрики их классов
|
||||||
|
#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); }},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Пример использования:
|
||||||
|
|
||||||
|
WORLDS_LIST {
|
||||||
|
GENERATE_WORLD_FACTORY(Sometime_class_world_One, WorldName_One)
|
||||||
|
GENERATE_WORLD_FACTORY(Sometime_class_world_Two, WorldName_Two)
|
||||||
|
};
|
||||||
|
*/
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
std::mutex mOutput;
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
void Log(const char* msg)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(mOutput);
|
||||||
|
std::cout << msg << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log(const std::string& msg)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(mOutput);
|
||||||
|
std::cout << msg << '\n';
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void Log(const char* msg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Log(const std::string& msg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Message(const char* msg)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(mOutput);
|
||||||
|
std::cout << msg << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
void Message(const std::string& msg)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(mOutput);
|
||||||
|
std::cout << msg << '\n';
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#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);
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#include "Vector.h"
|
||||||
|
|
||||||
|
#include "Game/SaveMap/SaveMap.h"
|
||||||
|
|
||||||
|
Vector2D::Vector2D(const double x, const double y) : x(x), y(y)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Vector2D::Vector2D(const Vector3D& vec3D) : x(vec3D.x), y(vec3D.y)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Vector2D Vector2D::operator+(const Vector2D& v) const
|
||||||
|
{
|
||||||
|
return Vector2D{ x + v.x, y + v.y };
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2D Vector2D::operator-(const Vector2D& v) const
|
||||||
|
{
|
||||||
|
return Vector2D{ x - v.x, y - v.y };
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> Vector2D::save()
|
||||||
|
{
|
||||||
|
std::unique_ptr<SaveMap> save = std::make_unique<SaveMap>("Vector2D");
|
||||||
|
save->SaveDouble("x", x)->SaveDouble("y", y);
|
||||||
|
return save;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vector2D::load(std::shared_ptr<SaveMap> save)
|
||||||
|
{
|
||||||
|
x = save->GetDouble("x");
|
||||||
|
y = save->GetDouble("y");
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3D::Vector3D(const double x, const double y, const double z) : x(x), y(y), z(z)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Vector3D::Vector3D(const Vector2D& vec2D) : x(vec2D.x), y(vec2D.y)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Vector3D Vector3D::operator+(const Vector3D& v) const
|
||||||
|
{
|
||||||
|
return Vector3D{x + v.x, y + v.y, z + v.z};
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3D Vector3D::operator-(const Vector3D& v) const
|
||||||
|
{
|
||||||
|
return Vector3D{ x - v.x, y - v.y, z - v.z };
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> Vector3D::save()
|
||||||
|
{
|
||||||
|
std::unique_ptr<SaveMap> save = std::make_unique<SaveMap>("Vector3D");
|
||||||
|
save->SaveDouble("x", x)->SaveDouble("y", y)->SaveDouble("z", z);
|
||||||
|
return save;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Vector3D::load(std::shared_ptr<SaveMap> save)
|
||||||
|
{
|
||||||
|
x = save->GetDouble("x");
|
||||||
|
y = save->GetDouble("y");
|
||||||
|
z = save->GetDouble("z");
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Game/SaveMap/ISave.h"
|
||||||
|
|
||||||
|
struct Vector3D;
|
||||||
|
|
||||||
|
struct Vector2D : public ISave {
|
||||||
|
double x = 0, y = 0;
|
||||||
|
|
||||||
|
Vector2D() = default;
|
||||||
|
Vector2D(const double x, const double y);
|
||||||
|
Vector2D(const Vector3D& vec3D);
|
||||||
|
|
||||||
|
Vector2D operator+(const Vector2D& v) const;
|
||||||
|
Vector2D operator-(const Vector2D& v) const;
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> save() override;
|
||||||
|
void load(std::shared_ptr<SaveMap> save) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Vector3D : public ISave {
|
||||||
|
double x = 0, y = 0, z = 0;
|
||||||
|
|
||||||
|
Vector3D() = default;
|
||||||
|
Vector3D(const double x, const double y, const double z);
|
||||||
|
Vector3D(const Vector2D& vec2D);
|
||||||
|
|
||||||
|
Vector3D operator+(const Vector3D& v) const;
|
||||||
|
Vector3D operator-(const Vector3D& v) const;
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> save() override;
|
||||||
|
void load(std::shared_ptr<SaveMap> save) override;
|
||||||
|
};
|
||||||
@@ -0,0 +1,333 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
template<typename TypeParameter>
|
||||||
|
class Delegate
|
||||||
|
{
|
||||||
|
struct DelegateDataBase
|
||||||
|
{
|
||||||
|
virtual ~DelegateDataBase() = default;
|
||||||
|
DelegateDataBase* next = nullptr;
|
||||||
|
long long Hash = 0;
|
||||||
|
virtual void Call(TypeParameter) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct DelegateDataForClass : DelegateDataBase
|
||||||
|
{
|
||||||
|
T* object = nullptr;
|
||||||
|
|
||||||
|
typedef void(T::*Method)(TypeParameter);
|
||||||
|
Method method = nullptr;
|
||||||
|
|
||||||
|
void Call(TypeParameter data) override
|
||||||
|
{
|
||||||
|
(object->*method)(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DelegateDataForFunction : DelegateDataBase
|
||||||
|
{
|
||||||
|
typedef void(*Func)(TypeParameter);
|
||||||
|
Func func = nullptr;
|
||||||
|
|
||||||
|
void Call(TypeParameter data) override
|
||||||
|
{
|
||||||
|
func(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DelegateDataBase* firstElement = nullptr;
|
||||||
|
|
||||||
|
std::mutex mDelegateList;
|
||||||
|
|
||||||
|
static constexpr unsigned int FNV1a(const char* str, unsigned int n, unsigned int hash = 2166136261U) {
|
||||||
|
return n == 0 ? hash : FNV1a(str + 1, n - 1, (hash ^ str[0]) * 19777619U);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
template<typename T>
|
||||||
|
void bind(T* object, void(T::*method)(TypeParameter))
|
||||||
|
{
|
||||||
|
char* str = new char[sizeof(T*) + sizeof(void(T::*)(TypeParameter))];
|
||||||
|
const char* ptrToObjectRef = reinterpret_cast<const char*>(&object);
|
||||||
|
for (long unsigned int i = 0; i < sizeof(T*); ++i)
|
||||||
|
str[i] = ptrToObjectRef[i];
|
||||||
|
|
||||||
|
const char* ptrToMethodRef = reinterpret_cast<const char*>(&method);
|
||||||
|
for (long unsigned int i = sizeof(T*); i < sizeof(T*) + sizeof(void(T::*)(TypeParameter)); ++i)
|
||||||
|
str[i] = ptrToMethodRef[i - sizeof(T*)];
|
||||||
|
|
||||||
|
DelegateDataForClass<T>* data = new DelegateDataForClass<T>;
|
||||||
|
data->next = firstElement;
|
||||||
|
data->object = object;
|
||||||
|
data->method = method;
|
||||||
|
data->Hash = FNV1a(str, sizeof(T*) + sizeof(void(T::*)(TypeParameter)));
|
||||||
|
|
||||||
|
delete[] str;
|
||||||
|
|
||||||
|
mDelegateList.lock();
|
||||||
|
firstElement = data;
|
||||||
|
mDelegateList.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind(void(*func)(TypeParameter))
|
||||||
|
{
|
||||||
|
char* str = new char[sizeof(void(*)(TypeParameter))];
|
||||||
|
const char* ptrToFuncRef = reinterpret_cast<const char*>(&func);
|
||||||
|
for (int i = 0; i < sizeof(void(*)(TypeParameter)); ++i)
|
||||||
|
str[i] = ptrToFuncRef[i];
|
||||||
|
|
||||||
|
DelegateDataForFunction* data = new DelegateDataForFunction;
|
||||||
|
data->next = firstElement;
|
||||||
|
data->func = func;
|
||||||
|
data->Hash = FNV1a(str, sizeof(func));
|
||||||
|
delete[] str;
|
||||||
|
|
||||||
|
mDelegateList.lock();
|
||||||
|
firstElement = data;
|
||||||
|
mDelegateList.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void unbind(T* object, void(T::*method)(TypeParameter))
|
||||||
|
{
|
||||||
|
if (firstElement == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char* str = new char[sizeof(T*) + sizeof(void(T::*)(TypeParameter))];
|
||||||
|
const char* ptrToObjectRef = reinterpret_cast<const char*>(&object);
|
||||||
|
for (long unsigned int i = 0; i < 8; ++i)
|
||||||
|
str[i] = ptrToObjectRef[i];
|
||||||
|
|
||||||
|
const char* ptrToMethodRef = reinterpret_cast<const char*>(&method);
|
||||||
|
for (long unsigned int i = sizeof(T*); i < sizeof(T*) + sizeof(void(T::*)(TypeParameter)); ++i)
|
||||||
|
str[i] = ptrToMethodRef[i - sizeof(T*)];
|
||||||
|
|
||||||
|
unsigned int Hash = FNV1a(str, sizeof(T*) + sizeof(void(T::*)(TypeParameter)));
|
||||||
|
|
||||||
|
DelegateDataBase* iterator = firstElement;
|
||||||
|
DelegateDataBase* temp = nullptr;
|
||||||
|
while (iterator != nullptr)
|
||||||
|
{
|
||||||
|
if (iterator->Hash == Hash)
|
||||||
|
{
|
||||||
|
if (temp != nullptr)
|
||||||
|
temp->next = iterator->next;
|
||||||
|
else
|
||||||
|
firstElement = iterator->next;
|
||||||
|
|
||||||
|
delete static_cast<DelegateDataForClass<T>*>(iterator);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp = iterator;
|
||||||
|
iterator = iterator->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void unbind(void(*func)(TypeParameter))
|
||||||
|
{
|
||||||
|
char* str = new char[sizeof(void(*)(TypeParameter))];
|
||||||
|
const char* ptrToFuncRef = reinterpret_cast<const char*>(&func);
|
||||||
|
for (int i = 0; i < sizeof(void(*)(TypeParameter)); ++i)
|
||||||
|
str[i] = ptrToFuncRef[i];
|
||||||
|
|
||||||
|
unsigned int Hash = FNV1a(str, sizeof(void(*)(TypeParameter)));
|
||||||
|
delete[] str;
|
||||||
|
|
||||||
|
DelegateDataBase* iterator = firstElement;
|
||||||
|
DelegateDataBase* temp = nullptr;
|
||||||
|
while (iterator != nullptr)
|
||||||
|
{
|
||||||
|
if (iterator->Hash == Hash)
|
||||||
|
{
|
||||||
|
if (temp != nullptr)
|
||||||
|
temp->next = iterator->next;
|
||||||
|
else
|
||||||
|
firstElement = iterator->next;
|
||||||
|
|
||||||
|
delete static_cast<DelegateDataForFunction*>(iterator);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp = iterator;
|
||||||
|
iterator = iterator->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Call(TypeParameter data) const
|
||||||
|
{
|
||||||
|
DelegateDataBase* iterator = firstElement;
|
||||||
|
while (iterator != nullptr)
|
||||||
|
{
|
||||||
|
iterator->Call(data);
|
||||||
|
iterator = iterator->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class Delegate<void>
|
||||||
|
{
|
||||||
|
struct DelegateDataBase
|
||||||
|
{
|
||||||
|
virtual ~DelegateDataBase() = default;
|
||||||
|
DelegateDataBase* next = nullptr;
|
||||||
|
long long Hash = 0;
|
||||||
|
virtual void call() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct DelegateDataForClass : DelegateDataBase
|
||||||
|
{
|
||||||
|
T* object = nullptr;
|
||||||
|
|
||||||
|
typedef void(T::*Method)();
|
||||||
|
Method method = nullptr;
|
||||||
|
|
||||||
|
void call() override
|
||||||
|
{
|
||||||
|
(object->*method)();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DelegateDataForFunction : DelegateDataBase
|
||||||
|
{
|
||||||
|
typedef void(*Func)();
|
||||||
|
Func func = nullptr;
|
||||||
|
|
||||||
|
void call() override
|
||||||
|
{
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DelegateDataBase* firstElement = nullptr;
|
||||||
|
|
||||||
|
std::mutex mDelegateList;
|
||||||
|
|
||||||
|
static constexpr unsigned int FNV1a(const char* str, unsigned int n, unsigned int hash = 2166136261U) {
|
||||||
|
return n == 0 ? hash : FNV1a(str + 1, n - 1, (hash ^ str[0]) * 19777619U);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
template<typename T>
|
||||||
|
void bind(T* object, void(T::*method)())
|
||||||
|
{
|
||||||
|
char* str = new char[sizeof(T*) + sizeof(void(T::*)())];
|
||||||
|
const char* ptrToObjectRef = reinterpret_cast<const char*>(&object);
|
||||||
|
for (int i = 0; i < sizeof(T*); ++i)
|
||||||
|
str[i] = ptrToObjectRef[i];
|
||||||
|
|
||||||
|
const char* ptrToMethodRef = reinterpret_cast<const char*>(&method);
|
||||||
|
for (int i = sizeof(T*); i < sizeof(T*) + sizeof(void(T::*)()); ++i)
|
||||||
|
str[i] = ptrToMethodRef[i - sizeof(T*)];
|
||||||
|
|
||||||
|
DelegateDataForClass<T>* data = new DelegateDataForClass<T>;
|
||||||
|
data->next = firstElement;
|
||||||
|
data->object = object;
|
||||||
|
data->method = method;
|
||||||
|
data->Hash = FNV1a(str, sizeof(T*) + sizeof(void(T::*)()));
|
||||||
|
|
||||||
|
delete[] str;
|
||||||
|
|
||||||
|
mDelegateList.lock();
|
||||||
|
firstElement = data;
|
||||||
|
mDelegateList.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind(void(*func)())
|
||||||
|
{
|
||||||
|
char* str = new char[sizeof(func)];
|
||||||
|
const char* ptrToFuncRef = reinterpret_cast<const char*>(&func);
|
||||||
|
for (int i = 0; i < sizeof(void(*)()); ++i)
|
||||||
|
str[i] = ptrToFuncRef[i];
|
||||||
|
|
||||||
|
DelegateDataForFunction* data = new DelegateDataForFunction;
|
||||||
|
data->next = firstElement;
|
||||||
|
data->func = func;
|
||||||
|
data->Hash = FNV1a(str, 8);
|
||||||
|
delete[] str;
|
||||||
|
|
||||||
|
mDelegateList.lock();
|
||||||
|
firstElement = data;
|
||||||
|
mDelegateList.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void unbind(T* object, void(T::*method)())
|
||||||
|
{
|
||||||
|
if (firstElement == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char* str = new char[sizeof(T*) + sizeof(void(T::*)())];
|
||||||
|
const char* ptrToObjectRef = reinterpret_cast<const char*>(&object);
|
||||||
|
for (int i = 0; i < sizeof(T*); ++i)
|
||||||
|
str[i] = ptrToObjectRef[i];
|
||||||
|
|
||||||
|
const char* ptrToMethodRef = reinterpret_cast<const char*>(&method);
|
||||||
|
for (int i = sizeof(T*); i < sizeof(T*) + sizeof(void(T::*)()); ++i)
|
||||||
|
str[i] = ptrToMethodRef[i - sizeof(T*)];
|
||||||
|
|
||||||
|
unsigned int Hash = FNV1a(str, sizeof(T*) + sizeof(void(T::*)()));
|
||||||
|
|
||||||
|
DelegateDataBase* iterator = firstElement;
|
||||||
|
DelegateDataBase* temp = nullptr;
|
||||||
|
while (iterator != nullptr)
|
||||||
|
{
|
||||||
|
if (iterator->Hash == Hash)
|
||||||
|
{
|
||||||
|
if (temp != nullptr)
|
||||||
|
temp->next = iterator->next;
|
||||||
|
else
|
||||||
|
firstElement = iterator->next;
|
||||||
|
|
||||||
|
delete static_cast<DelegateDataForClass<T>*>(iterator);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp = iterator;
|
||||||
|
iterator = iterator->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void unbind(void(*func)())
|
||||||
|
{
|
||||||
|
char* str = new char[sizeof(void(*)())];
|
||||||
|
const char* ptrToFuncRef = reinterpret_cast<const char*>(&func);
|
||||||
|
for (int i = 0; i < sizeof(void(*)()); ++i)
|
||||||
|
str[i] = ptrToFuncRef[i];
|
||||||
|
|
||||||
|
unsigned int Hash = FNV1a(str, sizeof(void(*)()));
|
||||||
|
delete[] str;
|
||||||
|
|
||||||
|
DelegateDataBase* iterator = firstElement;
|
||||||
|
DelegateDataBase* temp = nullptr;
|
||||||
|
while (iterator != nullptr)
|
||||||
|
{
|
||||||
|
if (iterator->Hash == Hash)
|
||||||
|
{
|
||||||
|
if (temp != nullptr)
|
||||||
|
temp->next = iterator->next;
|
||||||
|
else
|
||||||
|
firstElement = iterator->next;
|
||||||
|
|
||||||
|
delete static_cast<DelegateDataForFunction*>(iterator);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp = iterator;
|
||||||
|
iterator = iterator->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Call() const
|
||||||
|
{
|
||||||
|
DelegateDataBase* iterator = firstElement;
|
||||||
|
while (iterator != nullptr)
|
||||||
|
{
|
||||||
|
iterator->call();
|
||||||
|
iterator = iterator->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# Delegate
|
||||||
|
That library implement delegate for C++.
|
||||||
|
|
||||||
|
--------Exemple-------
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "Delegate.h"
|
||||||
|
|
||||||
|
class A
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Foo1(int var) { std::cout << "A::Foo1(" << var <<");\n"; }
|
||||||
|
void Foo2(int var) { std::cout << "A::Foo2(" << var <<");\n"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
Delegate<int> delegate;
|
||||||
|
A a;
|
||||||
|
delegate.bind(&a, &A::Foo1);
|
||||||
|
delegate.bind(&a, &A::Foo2);
|
||||||
|
delegate.unbind(&a, &A::Foo1);
|
||||||
|
delegate.Call(321);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
file(GLOB SRC "*.cpp" "*.h")
|
||||||
|
|
||||||
|
add_library(FastRTTI STATIC ${SRC})
|
||||||
|
|
||||||
|
target_include_directories(FastRTTI
|
||||||
|
PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||||
|
if(MSVC)
|
||||||
|
target_compile_options(FastRTTI PRIVATE /GR-)
|
||||||
|
target_link_options(FastRTTI PRIVATE /LTCG)
|
||||||
|
else()
|
||||||
|
# GCC / Clang
|
||||||
|
target_compile_options(FastRTTI PRIVATE -fno-rtti)
|
||||||
|
target_link_options(FastRTTI PRIVATE -flto)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
elseif(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
|
if(MSVC)
|
||||||
|
target_compile_options(FastRTTI PRIVATE /GR-)
|
||||||
|
else()
|
||||||
|
target_compile_options(FastRTTI PRIVATE
|
||||||
|
-g
|
||||||
|
-fno-rtti)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#include "RTTI.h"
|
||||||
|
|
||||||
|
void IRTTI::FastContainer::push_back(const Classes newType)
|
||||||
|
{
|
||||||
|
if (0 == _size)
|
||||||
|
{
|
||||||
|
++_size;
|
||||||
|
array = new Classes;
|
||||||
|
*array = newType;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++_size;
|
||||||
|
Classes* NewArray = new Classes[_size];
|
||||||
|
|
||||||
|
long long indexObject = _size - 1;
|
||||||
|
for (long long i = 0, j = 0; i < _size - 1; ++i, ++j)
|
||||||
|
{
|
||||||
|
if (newType < array[i] && indexObject == _size - 1)
|
||||||
|
{
|
||||||
|
indexObject = j;
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewArray[j] = array[i];
|
||||||
|
}
|
||||||
|
NewArray[indexObject] = newType;
|
||||||
|
|
||||||
|
delete[] array;
|
||||||
|
array = NewArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IRTTI::FastContainer::find(const Classes& Type) const
|
||||||
|
{
|
||||||
|
long long low = 0;
|
||||||
|
long long high = _size - 1;
|
||||||
|
|
||||||
|
while (low <= high)
|
||||||
|
{
|
||||||
|
long long mid = (low + high) / 2;
|
||||||
|
if (static_cast<int>(array[mid]) == static_cast<int>(Type))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (static_cast<int>(array[mid]) > static_cast<int>(Type))
|
||||||
|
high = mid - 1;
|
||||||
|
else
|
||||||
|
low = mid + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
IRTTI::FastContainer::~FastContainer()
|
||||||
|
{
|
||||||
|
_size = 0;
|
||||||
|
delete[] array;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRTTI::SetType(const Classes Type)
|
||||||
|
{
|
||||||
|
this->type = Type;
|
||||||
|
Tree.push_back(Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
IRTTI::IRTTI()
|
||||||
|
{
|
||||||
|
SetType(Classes::IRTTI);
|
||||||
|
}
|
||||||
|
|
||||||
|
Classes RTTI::GetType(const IRTTI* object)
|
||||||
|
{
|
||||||
|
return object->type;
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RTTI_Meta.h"
|
||||||
|
|
||||||
|
// Interface RTTI
|
||||||
|
GENERATE_META(IRTTI)
|
||||||
|
class IRTTI
|
||||||
|
{
|
||||||
|
// Fast array
|
||||||
|
class FastContainer final
|
||||||
|
{
|
||||||
|
long long _size = 0;
|
||||||
|
Classes* array = nullptr;
|
||||||
|
public:
|
||||||
|
long long constexpr size() const { return _size; }
|
||||||
|
void push_back(const Classes object);
|
||||||
|
bool find(const Classes& Type) const;
|
||||||
|
|
||||||
|
~FastContainer();
|
||||||
|
};
|
||||||
|
FastContainer Tree;
|
||||||
|
Classes type;
|
||||||
|
protected:
|
||||||
|
// That method set type value and add type to inheritance tree
|
||||||
|
void SetType(Classes Type);
|
||||||
|
|
||||||
|
IRTTI();
|
||||||
|
~IRTTI() = default;
|
||||||
|
|
||||||
|
friend class RTTI;
|
||||||
|
};
|
||||||
|
|
||||||
|
// RTTI methods
|
||||||
|
class RTTI final
|
||||||
|
{
|
||||||
|
RTTI() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<class Kind>
|
||||||
|
static bool IsA(const IRTTI* object)
|
||||||
|
{
|
||||||
|
return Meta<Kind>::Type == object->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// That method realized dynamic_cast
|
||||||
|
template<class To, class From>
|
||||||
|
static To* dyn_cast(From* object)
|
||||||
|
{
|
||||||
|
IRTTI* InterfaceOfObject = static_cast<IRTTI*>(object);
|
||||||
|
if (IsA<To>(object))
|
||||||
|
return static_cast<To*>(object);
|
||||||
|
|
||||||
|
if (InterfaceOfObject->Tree.find(Meta<To>::Type))
|
||||||
|
return static_cast<To*>(object);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// That method return real type object in the form of enum value
|
||||||
|
static Classes GetType(const IRTTI* object);
|
||||||
|
};
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// This macro adds meta information to a type
|
||||||
|
#define GENERATE_META(Class) \
|
||||||
|
class Class; \
|
||||||
|
template<> struct Meta <Class> { \
|
||||||
|
static constexpr Classes Type = Classes::Class; \
|
||||||
|
};
|
||||||
|
|
||||||
|
// Predeclared struct for meta information
|
||||||
|
template<class T> struct Meta;
|
||||||
|
|
||||||
|
// Enum type classes
|
||||||
|
enum class Classes
|
||||||
|
{
|
||||||
|
IRTTI, IResource, Actor, TestActor
|
||||||
|
};
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
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()
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#include "ModuleInstance.h"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
ModuleInstance::ModuleInstance(CoreInstance& core) : core_(core)
|
||||||
|
{
|
||||||
|
// Init instance
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModuleInstance::start()
|
||||||
|
{
|
||||||
|
// Create thread
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
mModuleInstance.lock();
|
||||||
|
if(module == nullptr)
|
||||||
|
module = Factory(core);
|
||||||
|
mModuleInstance.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartModule()
|
||||||
|
{
|
||||||
|
mModuleInstance.lock();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuitModule()
|
||||||
|
{
|
||||||
|
mModuleInstance.lock();
|
||||||
|
if(module != nullptr)
|
||||||
|
{
|
||||||
|
module->stop();
|
||||||
|
moduleThread->join();
|
||||||
|
delete module;
|
||||||
|
module = nullptr;
|
||||||
|
}
|
||||||
|
mModuleInstance.unlock();
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#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_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)); }
|
||||||
|
|
||||||
|
|
||||||
|
class CoreInstance;
|
||||||
|
|
||||||
|
class ModuleInstance {
|
||||||
|
CoreInstance& core_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Delegate<void> onStop;
|
||||||
|
|
||||||
|
ModuleInstance(CoreInstance& core);
|
||||||
|
virtual ~ModuleInstance() = default;
|
||||||
|
|
||||||
|
CoreInstance& getCore() const { return core_; }
|
||||||
|
|
||||||
|
virtual void start();
|
||||||
|
void stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
// Create module instance
|
||||||
|
EXPORT void InitModule(CoreInstance& core);
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp")
|
||||||
|
|
||||||
|
add_executable(ProjectGenerator ${SRC})
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
project(${GAME_NAME})
|
||||||
|
|
||||||
|
file(GLOB_RECURSE SRC "src/*.cpp" "src/*.c" "src/*.h" "src/*.hpp")
|
||||||
|
|
||||||
|
add_executable(${GAME_NAME} ${SRC})
|
||||||
|
|
||||||
|
target_link_directories(${GAME_NAME} PRIVATE
|
||||||
|
$<$<CONFIG:Debug>:$ENV{UwU_Engine}/bin/Debug>
|
||||||
|
$<$<CONFIG:Release>:$ENV{UwU_Engine}/bin/Release>
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(${GAME_NAME} PRIVATE Core FastRTTI)
|
||||||
|
target_include_directories(${GAME_NAME} PRIVATE
|
||||||
|
$ENV{UwU_Engine}/include/Core
|
||||||
|
$ENV{UwU_Engine}/include/FastRTTI
|
||||||
|
$ENV{UwU_Engine}/include/Delegate
|
||||||
|
)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
set(OUTPUT_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>)
|
||||||
|
else()
|
||||||
|
set(OUTPUT_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${GAME_NAME}
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/main_config.conf
|
||||||
|
${OUTPUT_PATH}/main_config.conf
|
||||||
|
COMMENT "Copying main config file"
|
||||||
|
)
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::string project_name;
|
||||||
|
std::cout << "Enter project name: ";
|
||||||
|
std::getline(std::cin, project_name);
|
||||||
|
|
||||||
|
std::filesystem::create_directory(project_name);
|
||||||
|
std::filesystem::create_directory(project_name + "/Resources");
|
||||||
|
std::filesystem::create_directory(project_name + "/Worlds");
|
||||||
|
std::filesystem::create_directory(project_name + "/src");
|
||||||
|
|
||||||
|
std::ifstream data("ProjectFile.txt");
|
||||||
|
std::string buffer = "cmake_minimum_required(VERSION 3.14)\nset(GAME_NAME " + project_name + ")\n";
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(data, line))
|
||||||
|
buffer += line + '\n';
|
||||||
|
data.close();
|
||||||
|
|
||||||
|
std::ofstream out(project_name + "/CMakeLists.txt", std::ios::out);
|
||||||
|
out << buffer;
|
||||||
|
out.close();
|
||||||
|
|
||||||
|
std::cout << "Project created successfully!\n";
|
||||||
|
system("pause");
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
set(GAME_NAME TestGame)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp" "*.res" "*.world" "*.conf")
|
||||||
|
|
||||||
|
add_executable(${GAME_NAME} ${SRC})
|
||||||
|
target_link_libraries(${GAME_NAME} PRIVATE Core)
|
||||||
|
target_include_directories(${GAME_NAME} PRIVATE
|
||||||
|
${PROJECT_SOURCE_DIR}/Core
|
||||||
|
${PROJECT_SOURCE_DIR}/FastRTTI
|
||||||
|
${PROJECT_SOURCE_DIR}/Delegate
|
||||||
|
)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
set(OUTPUT_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>)
|
||||||
|
else()
|
||||||
|
set(OUTPUT_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${GAME_NAME}
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/main_config.conf
|
||||||
|
${OUTPUT_PATH}/main_config.conf
|
||||||
|
COMMENT "Copying main config file"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${GAME_NAME}
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Worlds
|
||||||
|
${OUTPUT_PATH}/Worlds
|
||||||
|
COMMENT "Copying Worlds directory"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${GAME_NAME}
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Resources
|
||||||
|
${OUTPUT_PATH}/Resources
|
||||||
|
COMMENT "Copying Resources directory"
|
||||||
|
)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
test_double: 12345.700000
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
test_int: 12345
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
test_long: 1234567890123456789
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
test_string: Hello, Danil!
|
||||||
|
test_string2: Hello, User!
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"Class name":"TestWorld","dtime":5.000000,"Parent parameters":{"Class name":"World","loActors":[]}}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"Class name":"MainConfig","sgame_name":"Test Game","sbase_world":"TestWorld","vsmodules_names":[]}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#include "TestActor.h"
|
||||||
|
|
||||||
|
#include "Log/Log.h"
|
||||||
|
|
||||||
|
void TestActor::BeginPlay()
|
||||||
|
{
|
||||||
|
Actor::BeginPlay();
|
||||||
|
Log("TestActor::BeginPlay");
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Game/Actors/Actor.h"
|
||||||
|
|
||||||
|
GENERATE_META(TestActor)
|
||||||
|
class TestActor final : public Actor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void BeginPlay() override;
|
||||||
|
};
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#include "Game/ObjectFactory.h"
|
||||||
|
|
||||||
|
#include "../Actors/TestActor.h"
|
||||||
|
|
||||||
|
FACTORIES_LIST{
|
||||||
|
GENERATE_FACTORY_OBJECT(TestActor)
|
||||||
|
};
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#include "Game/WorldFactory.h"
|
||||||
|
|
||||||
|
#include "../Worlds/TestWorld.h"
|
||||||
|
|
||||||
|
WORLDS_LIST{
|
||||||
|
GENERATE_WORLD_FACTORY(TestWorld, TestWorld)
|
||||||
|
};
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#include "TestGameInstance.h"
|
||||||
|
|
||||||
|
#include "Game/Resource/Resource.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "Game/SaveMap/SaveMap.h"
|
||||||
|
#include "Game/World/World.h"
|
||||||
|
GENERATE_FACTORY_GAME_INSTANCE(TestGameInstance)
|
||||||
|
|
||||||
|
TestGameInstance::TestGameInstance(CoreInstance& core) : GameInstance(core)
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Game/GameInstance.h"
|
||||||
|
|
||||||
|
class TestGameInstance : public GameInstance
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TestGameInstance(CoreInstance& core);
|
||||||
|
};
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#include "TestWorld.h"
|
||||||
|
|
||||||
|
#include "Game/GameInstance.h"
|
||||||
|
#include "Game/SaveMap/SaveMap.h"
|
||||||
|
#include "Log/Log.h"
|
||||||
|
|
||||||
|
TestWorld::TestWorld(GameInstance& game_instance) : World(game_instance)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void TestWorld::BeginPlay()
|
||||||
|
{
|
||||||
|
World::BeginPlay();
|
||||||
|
Log("TestWorld::BeginPlay");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestWorld::Tick(double delta_time)
|
||||||
|
{
|
||||||
|
World::Tick(delta_time);
|
||||||
|
|
||||||
|
time += delta_time;
|
||||||
|
if (time >= 10.0)
|
||||||
|
{
|
||||||
|
Message("TestWorld: Time out");
|
||||||
|
GetGameInstance().quit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> TestWorld::save()
|
||||||
|
{
|
||||||
|
std::shared_ptr<SaveMap> save = World::save();
|
||||||
|
std::shared_ptr<SaveMap> my_save = std::make_shared<SaveMap>("TestWorld");
|
||||||
|
my_save->SaveDouble("time", time)->connect_to(save);
|
||||||
|
return my_save;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestWorld::load(std::shared_ptr<SaveMap> save)
|
||||||
|
{
|
||||||
|
World::load(save->getParent());
|
||||||
|
time = save->GetDouble("time");
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Game/World/World.h"
|
||||||
|
|
||||||
|
class TestWorld final : public World
|
||||||
|
{
|
||||||
|
double time = 0;
|
||||||
|
public:
|
||||||
|
TestWorld(GameInstance& game_instance);
|
||||||
|
|
||||||
|
void BeginPlay() override;
|
||||||
|
void Tick(double delta_time) override;
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> save() override;
|
||||||
|
void load(std::shared_ptr<SaveMap> save) override;
|
||||||
|
};
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
@echo off
|
||||||
|
cd build
|
||||||
|
cmake --build . --config Debug
|
||||||
|
pause
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
@echo off
|
||||||
|
cd build
|
||||||
|
cmake --build . --config Release
|
||||||
|
pause
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
@echo off
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -A Win32
|
||||||
|
pause
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
@echo off
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -A x64
|
||||||
|
pause
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -DCMAKE_BUILD_TYPE=Release
|
||||||
Submodule
+1
Submodule glfw added at 8e15281d34
Reference in New Issue
Block a user