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