Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: toggle stream + new indexed fields api #151

Merged
merged 21 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ cc_test(
name = "test",
visibility = ["//visibility:private"],
copts = copts,
defines = [
"ECSACT_CORE_API=",
"ECSACT_DYNAMIC_API=",
],
srcs = [
"build_test.cc",
"//runtime:sources",
Expand Down
10 changes: 5 additions & 5 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ module(

bazel_dep(name = "rules_cc", version = "0.0.9")
bazel_dep(name = "bazel_skylib", version = "1.6.1")
bazel_dep(name = "rules_ecsact", version = "0.5.7")
bazel_dep(name = "ecsact_runtime", version = "0.6.9")
bazel_dep(name = "ecsact_lang_cpp", version = "0.4.7")
bazel_dep(name = "rules_ecsact", version = "0.5.8")
bazel_dep(name = "ecsact_runtime", version = "0.7.0")
bazel_dep(name = "ecsact_lang_cpp", version = "0.4.10")
bazel_dep(name = "boost.mp11", version = "1.83.0.bzl.1")
bazel_dep(name = "entt", version = "3.12.2")
bazel_dep(name = "ecsact_codegen", version = "0.4.1")
bazel_dep(name = "ecsact_cli", version = "0.3.16")
bazel_dep(name = "ecsact_codegen", version = "0.4.3")
bazel_dep(name = "ecsact_cli", version = "0.3.19")
bazel_dep(name = "xxhash", version = "0.8.2")
bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
bazel_dep(name = "boost.dll", version = "1.83.0.bzl.2")
Expand Down
7 changes: 6 additions & 1 deletion build_test.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Include all headers fot the sake of a quick build test
// Include all headers for the sake of a quick build test
#include "entt/entt.hpp" // IWYU pragma: keep
#include "ecsact/entt/detail/apply_pending.hh" // IWYU pragma: keep
#include "ecsact/entt/detail/bytes.hh" // IWYU pragma: keep
Expand All @@ -8,13 +8,17 @@
#include "ecsact/entt/detail/internal_markers.hh" // IWYU pragma: keep
#include "ecsact/entt/detail/registry.hh" // IWYU pragma: keep
#include "ecsact/entt/detail/system_execution_context.hh" // IWYU pragma: keep
#include "ecsact/entt/detail/apply_component_stream_data.hh" // IWYU pragma: keep
#include "ecsact/entt/entity.hh" // IWYU pragma: keep
#include "ecsact/entt/error_check.hh" // IWYU pragma: keep
#include "ecsact/entt/event_markers.hh" // IWYU pragma: keep
#include "ecsact/entt/execution.hh" // IWYU pragma: keep
#include "ecsact/entt/registry_util.hh" // IWYU pragma: keep
#include "ecsact/entt/wrapper/core.hh" // IWYU pragma: keep
#include "ecsact/entt/wrapper/dynamic.hh" // IWYU pragma: keep
#include "ecsact/entt/stream_registries.hh" // IWYU pragma: keep
#include "ecsact/runtime/common.h" // IWYU pragma: keep
#include "entt/entity/registry.hpp" // IWYU pragma: keep

// default assign some global vars for the sake of compiling only
#define MOCK_DEF_GLOBAL(Name) \
Expand All @@ -30,6 +34,7 @@ MOCK_DEF_GLOBAL(has_component_fns);
MOCK_DEF_GLOBAL(update_component_fns);
MOCK_DEF_GLOBAL(remove_component_fns);
MOCK_DEF_GLOBAL(exec_ctx_action_fns);
MOCK_DEF_GLOBAL(ecsact_stream_fns);

auto main() -> int {
// This is only here to get compile commands working
Expand Down
36 changes: 36 additions & 0 deletions ecsact/entt/detail/apply_component_stream_data.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#pragma once

#include <entt/entt.hpp>

#include "ecsact/entt/detail/internal_markers.hh"

namespace ecsact::entt::detail {
template<typename C>
auto apply_component_stream_data(
::entt::registry& main_reg,
::entt::registry& stream_reg
) -> void {
auto view = main_reg.template view<
C>(::entt::exclude<ecsact::entt::detail::run_on_stream<C>>);

for(auto entity : view) {
if(!stream_reg.any_of<C>(entity)) {
continue;
}

auto& in_component = stream_reg.get<C>(entity);
if(main_reg.any_of<C>(entity)) {
auto& current_comp = main_reg.get<C>(entity);

auto& beforechange =
main_reg.template get<exec_beforechange_storage<C>>(entity);

if(!beforechange.has_update_occurred) {
beforechange.value = current_comp;
beforechange.has_update_occurred = true;
}
current_comp = in_component;
}
}
}
} // namespace ecsact::entt::detail
17 changes: 17 additions & 0 deletions ecsact/entt/detail/globals.hh
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,20 @@
#include "ecsact/runtime/dynamic.h"
#include "ecsact/entt/detail/system_execution_context.hh"
#include "ecsact/entt/detail/registry.hh"
#include "ecsact/entt/stream_registries.hh"

/**
* A small set of globals expected to be available the ecsact_rt_entt_codegen
* generated source.
*/
namespace ecsact::entt::detail::globals {

/**
* Holds and handles the individual registries for each thread that's passed in
* from ecsact_stream.
*/
extern stream::stream_registries stream_registries;

/**
* Ecsact registry ID mapped to EnTT registry instance.
*/
Expand Down Expand Up @@ -91,6 +98,16 @@ extern const std::unordered_map< //
decltype(&ecsact_has_component)>
has_component_fns;

/**
* ecsact_stream fn pointers
*
* NOTE: This gets is filled in by ecsact_rt_entt_codegen
*/
extern const std::unordered_map< //
ecsact_component_id,
decltype(&ecsact_stream)>
ecsact_stream_fns;

/**
* ecsact_system_execution_context_action fn pointers
*
Expand Down
11 changes: 11 additions & 0 deletions ecsact/entt/detail/internal_markers.hh
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ struct pending_add<C> {
template<typename C>
struct pending_remove {};

/**
* This flag is added to a system when its requirements contain a streaming
* component. If the ecsact_stream is toggled to systems, this component gets
* added and systems will run.
*/
template<typename C>
struct run_on_stream {};

struct created_entity {
ecsact_placeholder_entity_id placeholder_entity_id;
};
Expand All @@ -66,6 +74,9 @@ struct system_sorted {
template<typename S>
struct pending_lazy_execution {};

/**
* Flags a notify system to run upon fulfilling its requirements
*/
template<typename S>
struct run_system {};

Expand Down
18 changes: 14 additions & 4 deletions ecsact/entt/detail/system_execution_context.hh
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,25 @@ struct ecsact_system_execution_context {
) -> void = 0;

virtual auto remove( //
ecsact_component_like_id component_id
ecsact_component_like_id component_id,
const void* indexed_fields
) -> void = 0;

virtual auto get( //
ecsact_component_like_id component_id,
void* out_component_data
void* out_component_data,
const void* indexed_fields
) -> void = 0;

virtual auto update( //
ecsact_component_like_id component_id,
const void* component_data
const void* component_data,
const void* indexed_fields
) -> void = 0;

virtual auto has( //
ecsact_component_like_id component_id
ecsact_component_like_id component_id,
const void* indexed_fields
) -> bool = 0;

virtual auto generate( //
Expand All @@ -60,6 +64,12 @@ struct ecsact_system_execution_context {
const void** components_data
) -> void = 0;

virtual auto stream_toggle( //
ecsact_component_id component_id,
bool enable_stream,
const void* indexed_fields
) -> void = 0;

virtual auto parent() -> const ecsact_system_execution_context* = 0;

virtual auto other( //
Expand Down
2 changes: 2 additions & 0 deletions ecsact/entt/registry_util.hh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ inline auto create_registry()
);
auto& registry = registries[registry_id];

ecsact::entt::detail::globals::stream_registries.add_registry(registry_id);

return {registry_id, std::ref(registry)};
}

Expand Down
84 changes: 84 additions & 0 deletions ecsact/entt/stream_registries.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#pragma once

#include <thread>
#include <map>
#include <mutex>
#include <shared_mutex>
#include <vector>
#include <ranges>
#include <memory>
#include <entt/entt.hpp>
#include "ecsact/runtime/common.h"
#include "ecsact/entt/entity.hh"

namespace ecsact::entt::stream::detail {
using child_reg_thread_map =
std::unordered_map<std::thread::id, std::unique_ptr<::entt::registry>>;
using reg_thread_map =
std::unordered_map<ecsact_registry_id, child_reg_thread_map>;
} // namespace ecsact::entt::stream::detail

namespace ecsact::entt::stream {
class stream_registries {
private:
detail::reg_thread_map registry_stream_threads;
std::shared_mutex stream_mutex;

template<typename C>
auto ensure_and_add_entity_and_component(
std::unique_ptr<::entt::registry>& registry,
::ecsact::entt::entity_id entity,
const C& component
) -> void {
if(!registry->valid(entity)) {
auto new_entity = registry->create(entity);
assert(new_entity == entity.as_entt());
}

registry->template emplace_or_replace<C>(entity, component);
}

public:
stream_registries() = default;

template<typename C>
auto handle_stream(
ecsact_registry_id registry_id,
ecsact_entity_id entity_id,
const C& component
) -> void {
// Add to map if new threads/registries are introduced

auto thread_id = std::this_thread::get_id();
auto entity = ::ecsact::entt::entity_id(entity_id);

std::shared_lock shared_lk(stream_mutex);
std::unique_lock lk(stream_mutex, std::defer_lock);

auto reg_threads_itr = registry_stream_threads.find(registry_id);
assert(reg_threads_itr != registry_stream_threads.end());

auto& reg_threads = reg_threads_itr->second;
auto reg_thread_itr = reg_threads.find(thread_id);

if(reg_thread_itr == reg_threads.end()) {
auto registry = std::make_unique<::entt::registry>();
ensure_and_add_entity_and_component(registry, entity, component);
shared_lk.unlock();
lk.lock();
reg_threads.insert(
reg_threads.end(),
std::pair(thread_id, std::move(registry))
);
lk.unlock();
} else {
auto& registry = reg_thread_itr->second;
ensure_and_add_entity_and_component(registry, entity, component);
}
}

auto get_stream_registries()
-> std::vector<std::unique_ptr<::entt::registry>>;
auto add_registry(ecsact_registry_id) -> void;
};
} // namespace ecsact::entt::stream
Loading