18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci#include "component_query.h"
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include <base/containers/array_view.h>
198bf80f4bSopenharmony_ci#include <base/containers/iterator.h>
208bf80f4bSopenharmony_ci#include <base/containers/type_traits.h>
218bf80f4bSopenharmony_ci#include <base/containers/unordered_map.h>
228bf80f4bSopenharmony_ci#include <base/containers/vector.h>
238bf80f4bSopenharmony_ci#include <base/namespace.h>
248bf80f4bSopenharmony_ci#include <core/ecs/entity.h>
258bf80f4bSopenharmony_ci#include <core/ecs/intf_component_manager.h>
268bf80f4bSopenharmony_ci#include <core/ecs/intf_ecs.h>
278bf80f4bSopenharmony_ci#include <core/ecs/intf_entity_manager.h>
288bf80f4bSopenharmony_ci#include <core/log.h>
298bf80f4bSopenharmony_ci#include <core/namespace.h>
308bf80f4bSopenharmony_ci
318bf80f4bSopenharmony_ciCORE_BEGIN_NAMESPACE()
328bf80f4bSopenharmony_ciusing BASE_NS::array_view;
338bf80f4bSopenharmony_ciusing BASE_NS::move;
348bf80f4bSopenharmony_ci
358bf80f4bSopenharmony_ciComponentQuery::~ComponentQuery()
368bf80f4bSopenharmony_ci{
378bf80f4bSopenharmony_ci    UnregisterEcsListeners();
388bf80f4bSopenharmony_ci}
398bf80f4bSopenharmony_ci
408bf80f4bSopenharmony_cibool ComponentQuery::ResultRow::IsValidComponentId(size_t index) const
418bf80f4bSopenharmony_ci{
428bf80f4bSopenharmony_ci    if (index < components.size()) {
438bf80f4bSopenharmony_ci        return components[index] != IComponentManager::INVALID_COMPONENT_ID;
448bf80f4bSopenharmony_ci    }
458bf80f4bSopenharmony_ci    return false;
468bf80f4bSopenharmony_ci}
478bf80f4bSopenharmony_ci
488bf80f4bSopenharmony_civoid ComponentQuery::SetupQuery(
498bf80f4bSopenharmony_ci    const IComponentManager& baseComponentSet, const array_view<const Operation> operations, bool enableEntityLookup)
508bf80f4bSopenharmony_ci{
518bf80f4bSopenharmony_ci    const size_t componentCount = operations.size() + 1;
528bf80f4bSopenharmony_ci    enableLookup_ = enableEntityLookup;
538bf80f4bSopenharmony_ci
548bf80f4bSopenharmony_ci    result_.clear();
558bf80f4bSopenharmony_ci    valid_ = false;
568bf80f4bSopenharmony_ci
578bf80f4bSopenharmony_ci    // Unregistering any old listeners because the operations might not use the same managers.
588bf80f4bSopenharmony_ci    UnregisterEcsListeners();
598bf80f4bSopenharmony_ci
608bf80f4bSopenharmony_ci    managers_.clear();
618bf80f4bSopenharmony_ci    managers_.reserve(componentCount);
628bf80f4bSopenharmony_ci    operationMethods_.clear();
638bf80f4bSopenharmony_ci    operationMethods_.reserve(componentCount);
648bf80f4bSopenharmony_ci
658bf80f4bSopenharmony_ci    managers_.push_back(const_cast<IComponentManager*>(&baseComponentSet));
668bf80f4bSopenharmony_ci    operationMethods_.push_back(Operation::REQUIRE);
678bf80f4bSopenharmony_ci    for (auto& operation : operations) {
688bf80f4bSopenharmony_ci        managers_.push_back(const_cast<IComponentManager*>(&operation.target));
698bf80f4bSopenharmony_ci        CORE_ASSERT(managers_.back());
708bf80f4bSopenharmony_ci        operationMethods_.push_back(operation.method);
718bf80f4bSopenharmony_ci    }
728bf80f4bSopenharmony_ci
738bf80f4bSopenharmony_ci    if (enableListeners_) {
748bf80f4bSopenharmony_ci        RegisterEcsListeners();
758bf80f4bSopenharmony_ci    }
768bf80f4bSopenharmony_ci}
778bf80f4bSopenharmony_ci
788bf80f4bSopenharmony_cibool ComponentQuery::Execute()
798bf80f4bSopenharmony_ci{
808bf80f4bSopenharmony_ci    if (enableListeners_ && valid_) {
818bf80f4bSopenharmony_ci        // No changes detected since previous execute.
828bf80f4bSopenharmony_ci        return false;
838bf80f4bSopenharmony_ci    }
848bf80f4bSopenharmony_ci    if (managers_.empty()) {
858bf80f4bSopenharmony_ci        // Query setup not done.
868bf80f4bSopenharmony_ci        return false;
878bf80f4bSopenharmony_ci    }
888bf80f4bSopenharmony_ci    if (!managers_[0]) {
898bf80f4bSopenharmony_ci        // Base manager is null.
908bf80f4bSopenharmony_ci        return false;
918bf80f4bSopenharmony_ci    }
928bf80f4bSopenharmony_ci
938bf80f4bSopenharmony_ci    const IComponentManager& baseComponentSet = *managers_[0];
948bf80f4bSopenharmony_ci
958bf80f4bSopenharmony_ci    const auto baseComponents = baseComponentSet.GetComponentCount();
968bf80f4bSopenharmony_ci    result_.resize(baseComponents);
978bf80f4bSopenharmony_ci
988bf80f4bSopenharmony_ci    auto& em = baseComponentSet.GetEcs().GetEntityManager();
998bf80f4bSopenharmony_ci    const size_t managerCount = managers_.size();
1008bf80f4bSopenharmony_ci    size_t index = 0U;
1018bf80f4bSopenharmony_ci    for (IComponentManager::ComponentId id = 0; id < baseComponents; ++id) {
1028bf80f4bSopenharmony_ci        if (const Entity entity = baseComponentSet.GetEntity(id); em.IsAlive(entity)) {
1038bf80f4bSopenharmony_ci            auto& row = result_[index];
1048bf80f4bSopenharmony_ci            row.entity = entity;
1058bf80f4bSopenharmony_ci            row.components.resize(managerCount, IComponentManager::INVALID_COMPONENT_ID);
1068bf80f4bSopenharmony_ci            row.components[0U] = id;
1078bf80f4bSopenharmony_ci
1088bf80f4bSopenharmony_ci            bool valid = true;
1098bf80f4bSopenharmony_ci
1108bf80f4bSopenharmony_ci            // NOTE: starting from index 1 that is the first manager after the base component set.
1118bf80f4bSopenharmony_ci            for (size_t i = 1; valid && (i < managerCount); ++i) {
1128bf80f4bSopenharmony_ci                const auto& manager = managers_[i];
1138bf80f4bSopenharmony_ci                const auto componentId =
1148bf80f4bSopenharmony_ci                    manager ? manager->GetComponentId(entity) : IComponentManager::INVALID_COMPONENT_ID;
1158bf80f4bSopenharmony_ci                row.components[i] = componentId;
1168bf80f4bSopenharmony_ci
1178bf80f4bSopenharmony_ci                switch (operationMethods_[i]) {
1188bf80f4bSopenharmony_ci                    case Operation::REQUIRE: {
1198bf80f4bSopenharmony_ci                        // for required components ID must be valid
1208bf80f4bSopenharmony_ci                        valid = (componentId != IComponentManager::INVALID_COMPONENT_ID);
1218bf80f4bSopenharmony_ci                        break;
1228bf80f4bSopenharmony_ci                    }
1238bf80f4bSopenharmony_ci
1248bf80f4bSopenharmony_ci                    case Operation::OPTIONAL: {
1258bf80f4bSopenharmony_ci                        // for optional ID doesn't matter
1268bf80f4bSopenharmony_ci                        break;
1278bf80f4bSopenharmony_ci                    }
1288bf80f4bSopenharmony_ci
1298bf80f4bSopenharmony_ci                    default: {
1308bf80f4bSopenharmony_ci                        valid = false;
1318bf80f4bSopenharmony_ci                    }
1328bf80f4bSopenharmony_ci                }
1338bf80f4bSopenharmony_ci            }
1348bf80f4bSopenharmony_ci
1358bf80f4bSopenharmony_ci            if (valid) {
1368bf80f4bSopenharmony_ci                if (enableLookup_) {
1378bf80f4bSopenharmony_ci                    mapping_[entity] = index;
1388bf80f4bSopenharmony_ci                }
1398bf80f4bSopenharmony_ci                ++index;
1408bf80f4bSopenharmony_ci            }
1418bf80f4bSopenharmony_ci        }
1428bf80f4bSopenharmony_ci    }
1438bf80f4bSopenharmony_ci    result_.resize(index);
1448bf80f4bSopenharmony_ci
1458bf80f4bSopenharmony_ci    valid_ = true;
1468bf80f4bSopenharmony_ci    return true;
1478bf80f4bSopenharmony_ci}
1488bf80f4bSopenharmony_ci
1498bf80f4bSopenharmony_civoid ComponentQuery::Execute(
1508bf80f4bSopenharmony_ci    const IComponentManager& baseComponentSet, const array_view<const Operation> operations, bool enableEntityLookup)
1518bf80f4bSopenharmony_ci{
1528bf80f4bSopenharmony_ci    SetupQuery(baseComponentSet, operations, enableEntityLookup);
1538bf80f4bSopenharmony_ci    Execute();
1548bf80f4bSopenharmony_ci}
1558bf80f4bSopenharmony_ci
1568bf80f4bSopenharmony_civoid ComponentQuery::SetEcsListenersEnabled(bool enableListeners)
1578bf80f4bSopenharmony_ci{
1588bf80f4bSopenharmony_ci    enableListeners_ = enableListeners;
1598bf80f4bSopenharmony_ci    if (enableListeners_) {
1608bf80f4bSopenharmony_ci        RegisterEcsListeners();
1618bf80f4bSopenharmony_ci    } else {
1628bf80f4bSopenharmony_ci        UnregisterEcsListeners();
1638bf80f4bSopenharmony_ci    }
1648bf80f4bSopenharmony_ci}
1658bf80f4bSopenharmony_ci
1668bf80f4bSopenharmony_cibool ComponentQuery::IsValid() const
1678bf80f4bSopenharmony_ci{
1688bf80f4bSopenharmony_ci    return valid_;
1698bf80f4bSopenharmony_ci}
1708bf80f4bSopenharmony_ci
1718bf80f4bSopenharmony_ciarray_view<const ComponentQuery::ResultRow> ComponentQuery::GetResults() const
1728bf80f4bSopenharmony_ci{
1738bf80f4bSopenharmony_ci    return { result_.data(), result_.size() };
1748bf80f4bSopenharmony_ci}
1758bf80f4bSopenharmony_ci
1768bf80f4bSopenharmony_ciconst ComponentQuery::ResultRow* ComponentQuery::FindResultRow(Entity entity) const
1778bf80f4bSopenharmony_ci{
1788bf80f4bSopenharmony_ci    if (EntityUtil::IsValid(entity)) {
1798bf80f4bSopenharmony_ci        const auto it = mapping_.find(entity);
1808bf80f4bSopenharmony_ci        if (it != mapping_.end() && it->second < result_.size()) {
1818bf80f4bSopenharmony_ci            return &(result_[it->second]);
1828bf80f4bSopenharmony_ci        }
1838bf80f4bSopenharmony_ci    }
1848bf80f4bSopenharmony_ci
1858bf80f4bSopenharmony_ci    return nullptr;
1868bf80f4bSopenharmony_ci}
1878bf80f4bSopenharmony_ci
1888bf80f4bSopenharmony_civoid ComponentQuery::RegisterEcsListeners()
1898bf80f4bSopenharmony_ci{
1908bf80f4bSopenharmony_ci    if (!registered_ && !managers_.empty()) {
1918bf80f4bSopenharmony_ci        // Listen to changes in managers so the result can be automatically invalidated.
1928bf80f4bSopenharmony_ci        ecs_ = &managers_[0]->GetEcs();
1938bf80f4bSopenharmony_ci        for (auto& manager : managers_) {
1948bf80f4bSopenharmony_ci            if (manager) {
1958bf80f4bSopenharmony_ci                ecs_->AddListener(*manager, *this);
1968bf80f4bSopenharmony_ci            }
1978bf80f4bSopenharmony_ci        }
1988bf80f4bSopenharmony_ci        ecs_->AddListener(static_cast<IEcs::EntityListener&>(*this));
1998bf80f4bSopenharmony_ci        registered_ = true;
2008bf80f4bSopenharmony_ci    }
2018bf80f4bSopenharmony_ci}
2028bf80f4bSopenharmony_ci
2038bf80f4bSopenharmony_civoid ComponentQuery::UnregisterEcsListeners()
2048bf80f4bSopenharmony_ci{
2058bf80f4bSopenharmony_ci    if (registered_ && !managers_.empty() && ecs_) {
2068bf80f4bSopenharmony_ci        for (auto& manager : managers_) {
2078bf80f4bSopenharmony_ci            if (manager) {
2088bf80f4bSopenharmony_ci                ecs_->RemoveListener(*manager, *this);
2098bf80f4bSopenharmony_ci            }
2108bf80f4bSopenharmony_ci        }
2118bf80f4bSopenharmony_ci        ecs_->RemoveListener(static_cast<IEcs::EntityListener&>(*this));
2128bf80f4bSopenharmony_ci        registered_ = false;
2138bf80f4bSopenharmony_ci    }
2148bf80f4bSopenharmony_ci}
2158bf80f4bSopenharmony_ci
2168bf80f4bSopenharmony_civoid ComponentQuery::OnEntityEvent(const IEcs::EntityListener::EventType type, const array_view<const Entity> entities)
2178bf80f4bSopenharmony_ci{
2188bf80f4bSopenharmony_ci    if (!valid_) {
2198bf80f4bSopenharmony_ci        // Listener is only used to invalidate the quety. If the query is already invalid -> no need to check anything.
2208bf80f4bSopenharmony_ci        return;
2218bf80f4bSopenharmony_ci    }
2228bf80f4bSopenharmony_ci    if (type == IEcs::EntityListener::EventType::ACTIVATED || type == IEcs::EntityListener::EventType::DEACTIVATED) {
2238bf80f4bSopenharmony_ci        const auto managerCount = managers_.size();
2248bf80f4bSopenharmony_ci        for (const auto& entity : entities) {
2258bf80f4bSopenharmony_ci            // We are only interested in entities that have all the required managers.
2268bf80f4bSopenharmony_ci            bool isRelevantEntity = true;
2278bf80f4bSopenharmony_ci            for (size_t i = 0; i < managerCount; ++i) {
2288bf80f4bSopenharmony_ci                if (operationMethods_[i] == Operation::OPTIONAL) {
2298bf80f4bSopenharmony_ci                    continue;
2308bf80f4bSopenharmony_ci                }
2318bf80f4bSopenharmony_ci                if (managers_[i] && !managers_[i]->HasComponent(entity)) {
2328bf80f4bSopenharmony_ci                    // This entity is missing a required manager -> irrelevant.
2338bf80f4bSopenharmony_ci                    isRelevantEntity = false;
2348bf80f4bSopenharmony_ci                    break;
2358bf80f4bSopenharmony_ci                }
2368bf80f4bSopenharmony_ci            }
2378bf80f4bSopenharmony_ci
2388bf80f4bSopenharmony_ci            if (isRelevantEntity) {
2398bf80f4bSopenharmony_ci                // Marking this query as invalid. No need to iterate entities further.
2408bf80f4bSopenharmony_ci                valid_ = false;
2418bf80f4bSopenharmony_ci                return;
2428bf80f4bSopenharmony_ci            }
2438bf80f4bSopenharmony_ci        }
2448bf80f4bSopenharmony_ci    } else if (type == IEcs::EntityListener::EventType::DESTROYED) {
2458bf80f4bSopenharmony_ci        if (enableLookup_) {
2468bf80f4bSopenharmony_ci            for (const auto& entity : entities) {
2478bf80f4bSopenharmony_ci                mapping_.erase(entity);
2488bf80f4bSopenharmony_ci            }
2498bf80f4bSopenharmony_ci        }
2508bf80f4bSopenharmony_ci    }
2518bf80f4bSopenharmony_ci}
2528bf80f4bSopenharmony_ci
2538bf80f4bSopenharmony_civoid ComponentQuery::OnComponentEvent(const IEcs::ComponentListener::EventType type,
2548bf80f4bSopenharmony_ci    const IComponentManager& /* componentManager */, const array_view<const Entity> /* entities */)
2558bf80f4bSopenharmony_ci{
2568bf80f4bSopenharmony_ci    // We only get events from relevant managers. If they have new or deleted components, the query is no longer valid.
2578bf80f4bSopenharmony_ci    if (type == IEcs::ComponentListener::EventType::CREATED || type == IEcs::ComponentListener::EventType::DESTROYED) {
2588bf80f4bSopenharmony_ci        valid_ = false;
2598bf80f4bSopenharmony_ci    }
2608bf80f4bSopenharmony_ci}
2618bf80f4bSopenharmony_ciCORE_END_NAMESPACE()
262