State and enterprises register, move namespaces

This commit is contained in:
legatt 2025-07-04 18:20:45 +03:00
parent 80e025afed
commit 74042175f8
26 changed files with 227 additions and 81 deletions

1
ECSAPI/.gitignore vendored
View File

@ -154,6 +154,7 @@ install_manifest.txt
compile_commands.json compile_commands.json
CTestTestfile.cmake CTestTestfile.cmake
_deps _deps
CMakeUserPresets.json
### CMake Patch ### ### CMake Patch ###
# External projects # External projects

View File

@ -20,6 +20,7 @@
}, },
{ {
"name": "x64-debug", "name": "x64-debug",
"hidden": true,
"displayName": "x64 Debug", "displayName": "x64 Debug",
"inherits": "windows-base", "inherits": "windows-base",
"architecture": { "architecture": {
@ -32,6 +33,7 @@
}, },
{ {
"name": "x64-release", "name": "x64-release",
"hidden": true,
"displayName": "x64 Release", "displayName": "x64 Release",
"inherits": "x64-debug", "inherits": "x64-debug",
"cacheVariables": { "cacheVariables": {
@ -40,6 +42,7 @@
}, },
{ {
"name": "x86-debug", "name": "x86-debug",
"hidden": true,
"displayName": "x86 Debug", "displayName": "x86 Debug",
"inherits": "windows-base", "inherits": "windows-base",
"architecture": { "architecture": {
@ -52,6 +55,7 @@
}, },
{ {
"name": "x86-release", "name": "x86-release",
"hidden": true,
"displayName": "x86 Release", "displayName": "x86 Release",
"inherits": "x86-debug", "inherits": "x86-debug",
"cacheVariables": { "cacheVariables": {

View File

@ -1,10 +1,10 @@
// API to control world multithreaded processing in real time
#pragma once #pragma once
#include "data.hpp"
namespace ee_ecs namespace ee_ecs
{ {
void init(); void init(InitConfiguration config);
void start(); void start();
void stop(); void stop();

View File

@ -0,0 +1,13 @@
#pragma once
#include <unordered_map>
#include <ee_economy/economy.hpp>
namespace ee_ecs
{
struct InitConfiguration
{
std::unordered_map<short, ee_economy::container> states;
};
}

View File

@ -1,6 +1,9 @@
#pragma once #pragma once
#include "ee_economy/components/container.hpp"
#include <entt/entity/fwd.hpp>
#include <entt/entt.hpp> #include <entt/entt.hpp>
#include <ee_economy/economy.hpp> #include <ee_economy/economy.hpp>
#include <unordered_map>
namespace ee_ecs namespace ee_ecs
{ {
@ -9,21 +12,22 @@ namespace ee_ecs
private: private:
entt::registry registry; entt::registry registry;
std::unordered_map<short, entt::entity> states_table;
void update_enterprises();
public: public:
/// <summary> // Run every registered system
/// Run every registered system
/// </summary>
void update(); void update();
/// <summary> entt::entity register_state(const short id, const ee_economy::container &resources);
/// Register new enterprise entity in specified state
/// </summary>
/// <param name="action">represents type of activity that enterprise do every tick</param>
/// <param name="state">is ID of state entity where enterprise will be placed</param>
/// <param name="defaults">is initial properties of enterprise</param>
void spawn_enterprise(const bool is_building, const ACTION_TYPE action, const entt::entity state, const enterprise_defaults defaults);
entt::entity spawn_enterprise(
const bool is_building,
const ee_economy::ACTION_TYPE action,
const entt::entity state,
const ee_economy::enterprise_defaults &defaults
);
entt::registry& get_registry(); entt::registry& get_registry();
}; };

View File

@ -1,11 +1,15 @@
#include "ee_ecs/world.hpp"
#include <ee_ecs/ecs.hpp> #include <ee_ecs/ecs.hpp>
static ee_ecs::world world; static ee_ecs::world world_instance;
void ee_ecs::init() void ee_ecs::init(ee_ecs::InitConfiguration config)
{ {
for (auto& [id, container]: config.states)
{
world_instance.register_state(id, container);
}
} }
void ee_ecs::start() void ee_ecs::start()
@ -17,3 +21,4 @@ void ee_ecs::stop()
{ {
} }

View File

@ -1,35 +1,68 @@
#include <ee_economy/economy.hpp>
#include <ee_ecs/ecs.hpp> #include <ee_ecs/ecs.hpp>
#include <stdexcept>
void ee_ecs::world::update_enterprises()
{
ee_economy::mining(this->registry);
}
void ee_ecs::world::update() void ee_ecs::world::update()
{ {
mining(this->registry); this->update_enterprises();
} }
void ee_ecs::world::spawn_enterprise(const bool is_building, const ACTION_TYPE action, const entt::entity state, const enterprise_defaults defaults) entt::entity ee_ecs::world::register_state(const short id, const ee_economy::container &resources)
{
if (this->states_table.contains(id))
throw std::invalid_argument("State with this Id is already registered");
entt::entity entity = this->registry.create();
this->registry.emplace<ee_economy::state>(entity, id);
this->registry.emplace<ee_economy::container>(
entity,
resources.capacity,
resources.total,
resources.content
);
this->states_table[id] = entity;
return entity;
}
entt::entity ee_ecs::world::spawn_enterprise(
const bool is_building,
const ee_economy::ACTION_TYPE action,
const entt::entity state,
const ee_economy::enterprise_defaults &defaults
)
{ {
entt::entity entity = this->registry.create(); entt::entity entity = this->registry.create();
auto &enterprise_c = this->registry.emplace<enterprise>(entity); this->registry.emplace<ee_economy::enterprise>(entity, is_building, state);
enterprise_c.is_building = is_building;
enterprise_c.state = state;
auto &container_c = this->registry.emplace<container>(entity); this->registry.emplace<ee_economy::container>(
container_c = defaults.container; entity,
defaults.container.capacity,
defaults.container.total,
defaults.container.content
);
switch (action) switch (action)
{ {
case ACTION_TYPE::MINING: case ee_economy::ACTION_TYPE::MINING:
{ {
auto& miner_c = this->registry.emplace<miner>(entity); this->registry.emplace<ee_economy::miner>(entity, defaults.resource_target, defaults.base_efficiency_flat);
miner_c.resource = defaults.resource_target;
miner_c.value = defaults.base_efficiency_flat;
break; break;
} }
default: default:
break; break;
} }
return entity;
} }
entt::registry& ee_ecs::world::get_registry() {return this->registry;} entt::registry& ee_ecs::world::get_registry() {return this->registry;}

View File

@ -1,6 +1,6 @@
# List sources # List sources
set(SOURCES "test_conf.hpp" "main.cpp" "world.cpp") set(SOURCES "test_conf.hpp" "main.cpp" "world.cpp" "benchmark.cpp")
# Find dependencies # Find dependencies
@ -16,6 +16,10 @@ target_link_libraries(ecs_tests PRIVATE ECS::ECS)
# Test # Test
if (CMAKE_VERSION VERSION_GREATER 3.12)
set_property(TARGET ecs_tests PROPERTY CXX_STANDARD 20)
endif()
if (WIN32) if (WIN32)
add_custom_command( add_custom_command(
TARGET ecs_tests POST_BUILD TARGET ecs_tests POST_BUILD

View File

@ -0,0 +1,31 @@
#include <ee_ecs/ecs.hpp>
#include "test_conf.hpp"
#include <gtest/gtest.h>
#include <chrono>
struct timer final {
timer()
: start{std::chrono::system_clock::now()} {}
void elapsed() {
auto now = std::chrono::system_clock::now();
std::cout << std::chrono::duration<double>(now - start).count() << " seconds" << std::endl;
}
private:
std::chrono::time_point<std::chrono::system_clock> start;
};
template<typename Func, typename... Args>
void generic_with(Func func) {
timer timer;
func();
timer.elapsed();
}
TEST_F(WorldBenchmark, UpdateSystems)
{
generic_with([&]() {
world.update();
});
}

View File

@ -3,13 +3,30 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <ee_ecs/ecs.hpp> #include <ee_ecs/ecs.hpp>
struct WorldTest : testing::Test struct WorldBenchmark : testing::Test
{ {
ee_ecs::world world; ee_ecs::world world;
void SetUp() void SetUp()
{ {
for (short i = 0; i < 1000; i++)
{
ee_economy::container resources = {.capacity = 100.0};
resources.add(ee_economy::RESOURCE_TYPE::COAL, 100.0);
entt::entity state = world.register_state(i, resources);
ee_economy::enterprise_defaults miner = {
.container = {.capacity = 100.0},
.resource_target = ee_economy::RESOURCE_TYPE::GOLD,
.base_efficiency_flat = 1.0
};
world.spawn_enterprise(false, ee_economy::ACTION_TYPE::MINING, state, miner);
world.spawn_enterprise(false, ee_economy::ACTION_TYPE::MINING, state, miner);
world.spawn_enterprise(false, ee_economy::ACTION_TYPE::MINING, state, miner);
world.spawn_enterprise(false, ee_economy::ACTION_TYPE::MINING, state, miner);
world.spawn_enterprise(false, ee_economy::ACTION_TYPE::MINING, state, miner);
}
} }
void TearDown() void TearDown()

View File

@ -1,8 +1,35 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "test_conf.hpp"
#include <ee_ecs/ecs.hpp> #include <ee_ecs/ecs.hpp>
#include <ee_economy/economy.hpp>
#include <stdexcept>
TEST_F(WorldTest, SpawnEnterprise) TEST(WorldTest, RegisterState)
{ {
ASSERT_TRUE(true); ee_ecs::world world;
ee_economy::container res = {.capacity = 100.0};
res.add(ee_economy::RESOURCE_TYPE::COAL, 98.0);
entt::entity state = world.register_state(10, res);
ee_economy::state registered_state = world.get_registry().get<ee_economy::state>(state);
ee_economy::container registered_container = world.get_registry().get<ee_economy::container>(state);
ASSERT_EQ(registered_state.external_id, 10);
ASSERT_EQ(registered_container.content[ee_economy::RESOURCE_TYPE::COAL], 98.0);
}
TEST(WorldTest, RegisterStateDuplicate)
{
ee_ecs::world world;
world.register_state(10, {});
ASSERT_THROW({
world.register_state(10, {});
}, std::invalid_argument);
}
TEST(WorldTest, SpawnEnterprise)
{
ASSERT_TRUE(false);
} }

View File

@ -3,7 +3,7 @@
# List sources # List sources
set(HEADERS "economy.hpp" "defines.hpp" "enterprise_defaults.hpp" "systems.hpp") set(HEADERS "economy.hpp" "defines.hpp" "enterprise_defaults.hpp" "systems.hpp")
set(HEADERS_COMPONENTS "container.hpp" "enterprise.hpp" "miner.hpp" "producer.hpp" "tags.hpp") set(HEADERS_COMPONENTS "container.hpp" "enterprise.hpp" "miner.hpp" "producer.hpp" "state.hpp" "tags.hpp")
set(SOURCES "Economy.cpp") set(SOURCES "Economy.cpp")
set(SOURCES_SYSTEMS "mining.cpp") set(SOURCES_SYSTEMS "mining.cpp")

View File

@ -2,7 +2,7 @@
#include "../defines.hpp" #include "../defines.hpp"
#include <unordered_map> #include <unordered_map>
namespace ee_ecs namespace ee_economy
{ {
struct container struct container
{ {

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <entt/entt.hpp> #include <entt/entt.hpp>
namespace ee_ecs namespace ee_economy
{ {
struct enterprise struct enterprise
{ {

View File

@ -2,7 +2,7 @@
#include "../defines.hpp" #include "../defines.hpp"
#include <entt/entt.hpp> #include <entt/entt.hpp>
namespace ee_ecs namespace ee_economy
{ {
struct miner struct miner
{ {

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
namespace ee_ecs namespace ee_economy
{ {
struct producer struct producer
{ {

View File

@ -0,0 +1,8 @@
#pragma once
namespace ee_economy
{
struct state {
short external_id = -1;
};
}

View File

@ -1,8 +1,6 @@
#pragma once #pragma once
namespace ee_ecs namespace ee_economy
{ {
struct state {};
} }

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
namespace ee_ecs namespace ee_economy
{ {
const double TOLERANCE = 0.001; const double TOLERANCE = 0.001;

View File

@ -5,6 +5,7 @@
#include "systems.hpp" #include "systems.hpp"
#include "components/tags.hpp" #include "components/tags.hpp"
#include "components/state.hpp"
#include "components/container.hpp" #include "components/container.hpp"
#include "components/enterprise.hpp" #include "components/enterprise.hpp"
#include "components/miner.hpp" #include "components/miner.hpp"

View File

@ -2,7 +2,7 @@
#include "defines.hpp" #include "defines.hpp"
#include "components/container.hpp" #include "components/container.hpp"
namespace ee_ecs namespace ee_economy
{ {
struct enterprise_defaults struct enterprise_defaults
{ {

View File

@ -4,7 +4,7 @@
#include <unordered_map> #include <unordered_map>
#include "defines.hpp" #include "defines.hpp"
namespace ee_ecs namespace ee_economy
{ {
struct exchange_rule struct exchange_rule
{ {

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <entt/entt.hpp> #include <entt/entt.hpp>
namespace ee_ecs namespace ee_economy
{ {
void mining(entt::registry& registry); void mining(entt::registry& registry);
// void producing(entt::registry& registry); // void producing(entt::registry& registry);

View File

@ -1,6 +1,6 @@
#include <ee_economy/economy.hpp> #include <ee_economy/economy.hpp>
void ee_ecs::mining(entt::registry &registry) void ee_economy::mining(entt::registry &registry)
{ {
auto miners = registry.view<enterprise, miner, container>(); auto miners = registry.view<enterprise, miner, container>();

View File

@ -4,83 +4,83 @@
TEST_F(SystemsTest, MiningNormal) TEST_F(SystemsTest, MiningNormal)
{ {
ee_ecs::container &state_container = registry.get<ee_ecs::container>(state); ee_economy::container &state_container = registry.get<ee_economy::container>(state);
ee_ecs::container &miner_container = registry.get<ee_ecs::container>(miner); ee_economy::container &miner_container = registry.get<ee_economy::container>(miner);
ee_ecs::miner &miner_miner = registry.get<ee_ecs::miner>(miner); ee_economy::miner &miner_miner = registry.get<ee_economy::miner>(miner);
state_container.capacity = 15.0; state_container.capacity = 15.0;
state_container.add(ee_ecs::RESOURCE_TYPE::COAL, 10.0); state_container.add(ee_economy::RESOURCE_TYPE::COAL, 10.0);
miner_container.capacity = 5.0; miner_container.capacity = 5.0;
miner_miner.resource = ee_ecs::RESOURCE_TYPE::COAL; miner_miner.resource = ee_economy::RESOURCE_TYPE::COAL;
miner_miner.value = 0.1; miner_miner.value = 0.1;
ee_ecs::mining(registry); ee_economy::mining(registry);
ASSERT_DOUBLE_EQ(state_container.total, 9.9); ASSERT_DOUBLE_EQ(state_container.total, 9.9);
ASSERT_DOUBLE_EQ(state_container.content[ee_ecs::RESOURCE_TYPE::COAL], 9.9); ASSERT_DOUBLE_EQ(state_container.content[ee_economy::RESOURCE_TYPE::COAL], 9.9);
ASSERT_DOUBLE_EQ(miner_container.total, 0.1); ASSERT_DOUBLE_EQ(miner_container.total, 0.1);
ASSERT_DOUBLE_EQ(miner_container.content[ee_ecs::RESOURCE_TYPE::COAL], 0.1); ASSERT_DOUBLE_EQ(miner_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.1);
} }
TEST_F(SystemsTest, MiningEmptyState) TEST_F(SystemsTest, MiningEmptyState)
{ {
ee_ecs::container &state_container = registry.get<ee_ecs::container>(state); ee_economy::container &state_container = registry.get<ee_economy::container>(state);
ee_ecs::container &miner_container = registry.get<ee_ecs::container>(miner); ee_economy::container &miner_container = registry.get<ee_economy::container>(miner);
ee_ecs::miner &miner_miner = registry.get<ee_ecs::miner>(miner); ee_economy::miner &miner_miner = registry.get<ee_economy::miner>(miner);
state_container.capacity = 15.0; state_container.capacity = 15.0;
miner_container.capacity = 5.0; miner_container.capacity = 5.0;
miner_miner.resource = ee_ecs::RESOURCE_TYPE::COAL; miner_miner.resource = ee_economy::RESOURCE_TYPE::COAL;
miner_miner.value = 0.1; miner_miner.value = 0.1;
ee_ecs::mining(registry); ee_economy::mining(registry);
ASSERT_DOUBLE_EQ(state_container.total, 0.0); ASSERT_DOUBLE_EQ(state_container.total, 0.0);
ASSERT_DOUBLE_EQ(state_container.content[ee_ecs::RESOURCE_TYPE::COAL], 0.0); ASSERT_DOUBLE_EQ(state_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.0);
ASSERT_DOUBLE_EQ(miner_container.total, 0.0); ASSERT_DOUBLE_EQ(miner_container.total, 0.0);
ASSERT_DOUBLE_EQ(miner_container.content[ee_ecs::RESOURCE_TYPE::COAL], 0.0); ASSERT_DOUBLE_EQ(miner_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.0);
} }
TEST_F(SystemsTest, MiningPoorState) TEST_F(SystemsTest, MiningPoorState)
{ {
ee_ecs::container &state_container = registry.get<ee_ecs::container>(state); ee_economy::container &state_container = registry.get<ee_economy::container>(state);
ee_ecs::container &miner_container = registry.get<ee_ecs::container>(miner); ee_economy::container &miner_container = registry.get<ee_economy::container>(miner);
ee_ecs::miner &miner_miner = registry.get<ee_ecs::miner>(miner); ee_economy::miner &miner_miner = registry.get<ee_economy::miner>(miner);
state_container.capacity = 15.0; state_container.capacity = 15.0;
state_container.add(ee_ecs::RESOURCE_TYPE::COAL, 0.05); state_container.add(ee_economy::RESOURCE_TYPE::COAL, 0.05);
miner_container.capacity = 5.0; miner_container.capacity = 5.0;
miner_miner.resource = ee_ecs::RESOURCE_TYPE::COAL; miner_miner.resource = ee_economy::RESOURCE_TYPE::COAL;
miner_miner.value = 0.1; miner_miner.value = 0.1;
ee_ecs::mining(registry); ee_economy::mining(registry);
ASSERT_DOUBLE_EQ(state_container.total, 0.0); ASSERT_DOUBLE_EQ(state_container.total, 0.0);
ASSERT_DOUBLE_EQ(state_container.content[ee_ecs::RESOURCE_TYPE::COAL], 0.0); ASSERT_DOUBLE_EQ(state_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.0);
ASSERT_DOUBLE_EQ(miner_container.total, 0.05); ASSERT_DOUBLE_EQ(miner_container.total, 0.05);
ASSERT_DOUBLE_EQ(miner_container.content[ee_ecs::RESOURCE_TYPE::COAL], 0.05); ASSERT_DOUBLE_EQ(miner_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.05);
} }
TEST_F(SystemsTest, MiningReachCap) TEST_F(SystemsTest, MiningReachCap)
{ {
ee_ecs::container &state_container = registry.get<ee_ecs::container>(state); ee_economy::container &state_container = registry.get<ee_economy::container>(state);
ee_ecs::container &miner_container = registry.get<ee_ecs::container>(miner); ee_economy::container &miner_container = registry.get<ee_economy::container>(miner);
ee_ecs::miner &miner_miner = registry.get<ee_ecs::miner>(miner); ee_economy::miner &miner_miner = registry.get<ee_economy::miner>(miner);
state_container.capacity = 15.0; state_container.capacity = 15.0;
state_container.add(ee_ecs::RESOURCE_TYPE::COAL, 10.0); state_container.add(ee_economy::RESOURCE_TYPE::COAL, 10.0);
miner_container.capacity = 0.05; miner_container.capacity = 0.05;
miner_miner.resource = ee_ecs::RESOURCE_TYPE::COAL; miner_miner.resource = ee_economy::RESOURCE_TYPE::COAL;
miner_miner.value = 0.1; miner_miner.value = 0.1;
ee_ecs::mining(registry); ee_economy::mining(registry);
ASSERT_DOUBLE_EQ(state_container.total, 9.95); ASSERT_DOUBLE_EQ(state_container.total, 9.95);
ASSERT_DOUBLE_EQ(state_container.content[ee_ecs::RESOURCE_TYPE::COAL], 9.95); ASSERT_DOUBLE_EQ(state_container.content[ee_economy::RESOURCE_TYPE::COAL], 9.95);
ASSERT_DOUBLE_EQ(miner_container.total, 0.05); ASSERT_DOUBLE_EQ(miner_container.total, 0.05);
ASSERT_DOUBLE_EQ(miner_container.content[ee_ecs::RESOURCE_TYPE::COAL], 0.05); ASSERT_DOUBLE_EQ(miner_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.05);
} }

View File

@ -16,14 +16,14 @@ struct SystemsTest : testing::Test
{ {
// Create state // Create state
state = registry.create(); state = registry.create();
registry.emplace<ee_ecs::state>(state); registry.emplace<ee_economy::state>(state);
registry.emplace<ee_ecs::container>(state); registry.emplace<ee_economy::container>(state);
// Create miner enterprise // Create miner enterprise
miner = registry.create(); miner = registry.create();
registry.emplace<ee_ecs::enterprise>(miner, false, state); registry.emplace<ee_economy::enterprise>(miner, false, state);
registry.emplace<ee_ecs::miner>(miner); registry.emplace<ee_economy::miner>(miner);
registry.emplace<ee_ecs::container>(miner); registry.emplace<ee_economy::container>(miner);
} }
void TearDown() void TearDown()