Skip to content
This repository was archived by the owner on Jul 29, 2026. It is now read-only.

Dev - #300

Merged
ThorstenSuckow merged 3 commits into
mainfrom
dev
Apr 24, 2026
Merged

Dev#300
ThorstenSuckow merged 3 commits into
mainfrom
dev

Conversation

@ThorstenSuckow

Copy link
Copy Markdown
Owner

No description provided.

Copilot AI review requested due to automatic review settings April 24, 2026 20:10
@ThorstenSuckow
ThorstenSuckow merged commit 1686144 into main Apr 24, 2026
1 of 4 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates Helios ECS iteration and lifecycle handling by introducing “optional components” support in ecs::View and simplifying entity activation to rely solely on the Active tag.

Changes:

  • Refactors ecs::View into a PartialView model, adds withOptional<...>(), and extends iteration to yield nullptr for missing optional components.
  • Removes Inactive tag usage from Entity::setActive() and adjusts activation logic accordingly.
  • Updates documentation/comments around view iteration return values and activation behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
include/helios/ecs/View.ixx Introduces PartialView + View alias and adds optional-component iteration via withOptional<...>().
include/helios/ecs/Entity.ixx Simplifies activation toggling to only add/remove Active and updates related logic/docs.
Comments suppressed due to low confidence (1)

include/helios/ecs/Entity.ixx:301

  • The setActive doc comment still states that activating removes an Inactive tag component, but this function no longer adds/removes Inactive at all. Update the comment to match the new behavior, or reintroduce the Inactive tag handling if other parts of the ECS still expect it.
         * @details When deactivated:
         * - The `Active` tag component is removed
         * - `onDeactivate()` is called on components that support it
         * - If a `HierarchyComponent` is present, it is marked dirty for propagation
         *
         * When activated:
         * - The `Inactive` tag component is removed
         * - An `Active` tag component is added
         * - `onActivate()` is called on components that support it

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

std::vector<std::function<bool(EntityId)>> excludeChecks,
const bool filterEnabledOnly
) : em_(em), includeSets_(includeSets), excludeChecks_(std::move(excludeChecks)), filterEnabledOnly_(filterEnabledOnly) {
static_assert(sizeof...(TOptional) == 0, "withOptional() should provide all optional components types in a single call.");

Copilot AI Apr 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

withOptional() constructs a PartialView with a non-empty TOptional... pack, but this constructor unconditionally static_assert(sizeof...(TOptional) == 0). As written, any call to withOptional<...>() will fail to compile. Move the assertion/constraint onto withOptional() (e.g., require the current view to have no optional components) or remove it from this constructor and enforce the “single call” rule differently.

Suggested change
static_assert(sizeof...(TOptional) == 0, "withOptional() should provide all optional components types in a single call.");

Copilot uses AI. Check for mistakes.
Comment on lines +368 to +377
([filterEnabledOnly, entityId, &sets]() {
if (!sets || !sets->contains(entityId)) {
return nullptr;
}

auto* component = sets->get(entityId);

if constexpr (requires {component->isEnabled(); }) {
if (filterEnabledOnly && !component->isEnabled()) {
return nullptr;

Copilot AI Apr 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The optional-component IIFE lambda returns nullptr in some branches and a component pointer in others. With deduced auto return type, return nullptr; deduces std::nullptr_t, which won’t match TOptional* and typically fails return-type deduction. Explicitly specify the lambda return type (e.g., -> decltype(sets->get(entityId))) and cast nullptr to that pointer type in the early-return branches.

Suggested change
([filterEnabledOnly, entityId, &sets]() {
if (!sets || !sets->contains(entityId)) {
return nullptr;
}
auto* component = sets->get(entityId);
if constexpr (requires {component->isEnabled(); }) {
if (filterEnabledOnly && !component->isEnabled()) {
return nullptr;
([filterEnabledOnly, entityId, &sets]() -> decltype(sets->get(entityId)) {
if (!sets || !sets->contains(entityId)) {
return static_cast<decltype(sets->get(entityId))>(nullptr);
}
auto* component = sets->get(entityId);
if constexpr (requires {component->isEnabled(); }) {
if (filterEnabledOnly && !component->isEnabled()) {
return static_cast<decltype(sets->get(entityId))>(nullptr);

Copilot uses AI. Check for mistakes.
Comment on lines +312 to +325
bool isActive = entityManager_->template has<ActiveComponent_type>(entityHandle_);
bool isInActive = !isActive;

if (!isActive && active) {
auto* hc = entityManager_->template get<HierarchyComponent_type>(entityHandle_);
auto* hc = entityManager_->template get<HierarchyComponent_type>(entityHandle_);
if (hc) {
hc->markDirty();
}

entityManager_->template remove<InactiveComponent_type>(entityHandle_);
entityManager_->template emplaceOrGet<ActiveComponent_type>(entityHandle_);
entityManager_->template emplaceOrGet<ActiveComponent_type>(entityHandle_);
}

if (!isInActive && !active) {
auto* hc = entityManager_->template get<HierarchyComponent_type>(entityHandle_);
auto* hc = entityManager_->template get<HierarchyComponent_type>(entityHandle_);

Copilot AI Apr 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isInActive is now just !isActive, which makes the subsequent condition if (!isInActive && !active) equivalent to if (isActive && !active) but harder to read (and the name suggests an Inactive tag that’s no longer used). Consider simplifying the boolean logic and renaming to isInactive/wasActive (or removing the extra variable) to avoid confusion.

Copilot uses AI. Check for mistakes.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants